useState
直接更新状态。
useReducer
可以脱离了UI,可以独立复用。但无法像redux一样进行跨组件的状态共享。
对于拥有许多状态更新逻辑的组件来说,过于分散的事件处理程序可能会令人不知所措。对于这种情况,你可以将组件的所有状态更新逻辑整合到一个外部函数中,这个函数叫作 reducer。
使用 reducer 管理状态与直接设置状态略有不同。它不是通过设置状态来告诉 React “要做什么”,而是通过事件处理程序 dispatch 一个 “action” 来指明 “用户刚刚做了什么”。(而状态更新逻辑则保存在其他地方!)
function handleAddTask(text) {
// "action" 对象:
dispatch({
type: 'added',
id: nextId++,
text: text,
});
}
function handleChangeTask(task) {
dispatch({
type: 'changed',
task: task,
});
}
function handleDeleteTask(taskId) {
dispatch({
type: 'deleted',
id: taskId,
});
}
“action”是一个普通的 JavaScript 对象。它的结构是由你决定的,在后面的步骤中,你将会学习如何添加一个 dispatch
函数。
reducer 函数就是你放置状态逻辑的地方。它接受两个参数,分别为当前 state 和 action 对象,并且返回的是更新后的 state,如下(在 reducer 中使用 switch 语句 是一种惯例):
function tasksReducer(tasks, action) {
switch (action.type) {
case 'added': {
return [
...tasks,
{
id: action.id,
text: action.text,
done: false,
},
];
}
case 'changed': {
return tasks.map((t) => {
if (t.id === action.task.id) {
return action.task;
} else {
return t;
}
});
}
case 'deleted': {
return tasks.filter((t) => t.id !== action.id);
}
default: {
throw Error('未知 action: ' + action.type);
}
}
}
最后,在组件中导入taskReducer
import { useState } from 'react';
⬇️
import { useReducer } from 'react';
const [tasks, setTasks] = useState(initialTasks);
⬇️
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
useSelector、useDispatch
用法:首先通过reducer给state赋值num
const reducer = (state, action) => {
switch (action.type) {
case "decrement":
return { ...state, num: state.num - 1 };
case "increment":
return { ...state, num: state.num + 1 };
default:
return state;
}
}
先通过createStore将state存入redux store
const store = createStore(reducer, initialState);
接着通过provider把state传给子组件
const ComponentUseReactRedux = () => {
return (
<div>
<h2>ComponentUseReactRedux</h2>
<Provider store={store}>
<ChildComponentUseReactRedux />
</Provider>
</div>
)
}
最后在子组件里,useSelector负责读取和渲染状态,useDispatch负责触发状态更新
- 通过useSelector(选择器函数)从store全局状态里提取需要的部分,这里是state里的num。当 dispatch(action) 触发 reducer 修改状态后,Store 会通知所有订阅的组件。
- useSelector 会比较 上一次选择器返回值 和 新返回值: 如果不同(!==),组件重新渲染。 如果相同,组件不会重新渲染(避免不必要的更新)。
- useDispatch通过distpatch触发状态更新,dispatch(action) 是 Redux 中触发状态更新的唯一方式
const ChildComponentUseReactRedux = () => {
const num = useSelector(state => state.num);
const dispatch = useDispatch();
return (
<div>
<h3>Using useSelector, useDispatch</h3>
Number: {num}
//组件调用,dispatch(action),store传递state和action
//reducer会根据action计算新状态,store更新状态并通知组件
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
</div>
);
}