目录
前言
useReducer
使用useReducer写一个表单提交的案例
使用useReducer代替Redux
一、前言
前面已经介绍了useState 的详细用法,我们可以在函数组件和类组件中使用 useState 来创建变量和对象。使得页面能够及时的更新 UI 等等。接下来介绍一个 useState 的复杂版本–useReducer
二、useReducer
useReducer 是 useState 的升级版本,用来践行 Flux/Redux 的思想
它主要有两个参数,一个读接口 state,一个写接口 dispatch
要自己先定义好 state 状态量和 setState 的一些函数 API
参数列表:
useReducer(dispatch,state,init)
1、使用 useReducer
在页面中显示 n 的值,且按下按钮后会触发响应的操作使 n 值发生变化。其中的操作分别是使 n+1,n+2,nx2。
const initialState = {
n: 0,
};
const reducer = (state, action) => {
if (action.type === "add") {
/* 规则与useState一样必须返回新的对象,不然变量值不会改变 */
return { n: state.n + action.number };
} else if (action.type === "multi") {
return { n: state.n * action.number };
} else {
throw new Error("unknown type!");
}
};
/* 在函数组件中使用useReducer */
const App = () => {
const [state, dispatch] = useReducer(reducer, initialState);
const onclick1 = () => {
dispatch({ type: "add", number: 1 });
};
const onclick2 = () => {
dispatch({ type: "add", number: 2 });
};
const onclick3 = () => {
dispatch({ type: "multi", number: 2 });
};
return (
<div className="App">
<h1>n:{state.n}</h1>
<button onClick={onclick1}>+1</button>
<button onClick={onclick2}>+2</button>
<button onClick={onclick3}>x2</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
效果展示
在对+1、+2、x2 按钮一番按键后,改变了页面中的 n 值。
2、总结
用法与 useState 类似,从 useReducer 中得到读接口 state,写接口 dispatch。最后操作时传参给 dispatch 写接口。操作灵活多变,比 useState 好处就是能聚集所有的操作和各种状态量。着重理解这几行代码,读懂。
useReducer 算是 useState 的复杂版
使用 useReducer 分以下步骤:
创建初始值的状态initialState
创建所有对状态的操作reducer(state,action)
传给useReducer,得到读和写的接口
调用写({'type':'操作类型'})
三、使用 useReducer 写一个表单提交
写一个简单的表单,包含姓名,年龄,民族等信息。在下方显示输入表单的值的动态变化
const initialState = {
name: "",
age: 18,
nationality: "汉族",
};
const reducer = (state, action) => {
switch (action.type) {
case "patch":
return { ...state, ...action.formData };
case "reset":
return initialState;
default:
throw new Error("unknown type!");
}
};
/* 在函数组件中使用useReducer */
const App = () => {
const [formData, dispatch] = useReducer(reducer, initialState);
const onSubmit = () => {
alert("你点击了提交按钮");
};
const onReset = () => {
dispatch({ type: "reset" });
};
return (
<form onSubmit={onSubmit} onReset={onReset}>
<div>
<label>
姓名
<input
type="text"
value={formData.name}
onChange={(e) => {
dispatch({ type: "patch", formData: { name: e.target.value } });
}}
/>
</label>
</div>
<div>
<label>
年龄
<input
type="number"
value={formData.age}
onChange={(e) => {
dispatch({ type: "patch", formData: { name: e.target.value } });
}}
/>
</label>
</div>
<div>
<label>
民族
<input
type="text"
value={formData.nationality}
onChange={(e) => {
dispatch({
type: "patch",
formData: { nationality: e.target.value },
});
}}
/>
</label>
</div>
<div>
<button type="submit">提交</button>
<button type="reset">重置</button>
</div>
<hr />
{JSON.stringify(formData)}
</form>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
效果展示
我随意在输入框中输入一些东西,下面会及时的更新显示出来的输入的数据
四、使用 useReducer 代替 Redux
使用 createContext/useContext 模拟 Redux 的全局数据状态管理的作用域,useReducer 来表示全局数据状态管理中的所有读写操作。
在创建的上下文对象中能够及时更新数据,就类似于一个局部的 Redux。在以下代码中,案例
:我将模拟一个 state 有三个变量 n,m,p。一个组件更新,其他组件的值也会连带着更新。
1、案例代码
const store = {
n: 0,
m: 0,
p: 0,
};
const reducer = (state, action) => {
switch (action.type) {
case "setN":
return { ...state, n: state.n + action.number };
case "setM":
return { ...state, m: state.m + action.number };
case "setP":
return { ...state, p: state.p + action.number };
default:
throw new Error("unknown type!");
}
};
/* 创建上下文对象--模拟一个Redux的作用域 */
const Context = React.createContext(null);
const App = () => {
const [state, dispatch] = React.useReducer(reducer, store);
return (
<Context.Provider value={{ state, dispatch }}>
<N />
<M />
<P />
</Context.Provider>
);
};
const N = () => {
const { state, dispatch } = React.useContext(Context);
const addClick = () => {
dispatch({ type: "setN", number: 1 });
};
return (
<div>
<h1>N组件</h1>
<div>n:{state.n}</div>
<div>m:{state.m}</div>
<div>p:{state.p}</div>
<button onClick={addClick}>+1</button>
</div>
);
};
const M = () => {
const { state, dispatch } = React.useContext(Context);
const addClick = () => {
dispatch({ type: "setM", number: 2 });
};
return (
<div>
<h1>M组件</h1>
<div>n:{state.n}</div>
<div>m:{state.m}</div>
<div>p:{state.p}</div>
<button onClick={addClick}>+2</button>
</div>
);
};
const P = () => {
const { state, dispatch } = React.useContext(Context);
const addClick = () => {
dispatch({ type: "setP", number: 3 });
};
return (
<div>
<h1>P组件</h1>
<div>n:{state.n}</div>
<div>m:{state.m}</div>
<div>p:{state.p}</div>
<button onClick={addClick}>+3</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
效果展示
在一番对 n,m,p 数据的操作后,所有组件的值都变化了更新
2、使用 reducer 总结
- createContext/useContext 来作为一个模拟 Redux 的作用域
- useReducer 作为这个作用域中的对数据的所有读写操作
- 若 state 数据中有多个值或对象,要先使用
...state
拷贝原先的数据,在覆写要修改的数据。原因:【React 全解 1 state&setState】