目录
1,介绍
这也是官方的一个HOOK,目的是更方便的使用 Redux。
Redux 后续会详细介绍。它的主体思想沿用了 Flux 数据流框架(也是 FaceBook 出品的)的思想,Vuex 也是同样的实现。
1.1,Flux 的设计思想
-
数据是单项流动的。
-
数据存储在数据仓库
state
中(可以将useState
的state
简单理解为数据仓库)。 -
action
是改变数据的唯一原因 ,它本质上是一个对象,有2个属性type
,字符串,表示改变数据的动作类型;payload
,any类型,表示动作的附加信息,也就是额外的参数。
例如,添加一个学生:
{ type: 'addStu', payload: { 学生对象的各种信息 } }
例如,删除一个学生:
{ type: 'deleteStu', payload: 学生id }
-
reducer
改变数据的具体实现,是一个函数:- 有2个参数
state
,表示当前数据仓库中的数据;action
。
- 必须有返回值,表示数据仓库变化后的数据。另外,Flux 要求对象是不可变的,所以要修改
state
必须创建新的对象。 - 必须是纯函数,不能有任何副作用。
- 不能直接调用,必须通过辅助函数
dispatch
。
- 有2个参数
-
dispatch
是一个辅助函数,用于触发reducer
。该函数仅接收一个参数action
,并调用reducer
来改变state
。
2,实现
2.1,引入
先看个简单例子:
js
export default function App() {
const [n, setN] = useState(0);
return (
<div>
<button
onClick={() => {
setN(n - 1);
}}
>
-
</button>
<span>{n}</span>
<button
onClick={() => {
setN(n + 1);
}}
>
+
</button>
</div>
);
}
用 Flux 的思想改造:
js
function reducer(state, action) {
let newState = state;
if (action.type === "minus") {
newState = state <= 0 ? 0 : state - 1;
} else if (action.type === "add") {
newState = state + 1;
}
return newState;
}
export default function App() {
const [n, setN] = useState(0);
function dispatch(action) {
const newN = reducer(n, action);
setN(newN);
}
return (
<div>
<button
onClick={() => {
dispatch({ type: "minus" });
}}
>
-
</button>
<span>{n}</span>
<button
onClick={() => {
dispatch({ type: "add" });
}}
>
+
</button>
</div>
);
}
注意,通过 Flux 的思想,只是为了把逻辑拆分的更细,便于管理状态 state
。
我要改变数据(
dispatch
),至于如何实现(reducer
)并不关心。
而对使用状态的组件来说,影响并不大。因为完全可以直接使用 reducer
这个自定义函数。
2.2,实现 useReducer
dispatch
的实现很简单,所以可以考虑做成一个通用的 HOOK:useReducer
。
js
import { useState } from "react";
export const useReducer = (reducerFunc, initState) => {
const [state, setState] = useState(initState);
function dispatch(action) {
const newState = reducerFunc(state, action);
setState(newState);
}
return [state, dispatch];
};
使用:
js
export default function App() {
const [n, dispatch] = useReducer(reducer, 0);
// 其他内容...
}
3,官方实现
React 考虑到这一点,所以官方实现了 useReducer
这个HOOK函数,并且还有第3个可选参数:
该函数将 useReducer
的第2个参数作为它的参数,返回值作为 useReducer
中的 state
初始值。
js
import { useReducer } from "react";
改造下自己实现的:
js
import { useState } from "react";
/**
* 通用的useReducer函数
* @param { function } reducer reducer函数
* @param { any } initialState 初始状态
* @param { function } initFunc 计算初始值的函数
*/
export const useReducer = (reducerFunc, initState, initFunc) => {
const [state, setState] = useState(initFunc ? initFunc(initState) : initState);
function dispatch(action) {
const newState = reducerFunc(state, action);
setState(newState);
}
return [state, dispatch];
};
以上。