redux hooks

redux hooks

useReducer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import React, { useReducer } from "react";

const initialState = { num: 0 };

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;
}
};

const ComponentUseReducer = () => {
const [state, dispatch] = useReducer(reducer, initialState);

const { num } = state;
return (
<div>
<h2>Using useReducer</h2>
Number: {num}
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
</div>
);
};

export default ComponentUseReducer;

可以看到 useReducer 的逻辑脱离了 UI,可以独立复用。reducer 就是一个单纯的 Js 方法,我们可以对 reducer 进行单独测试,甚至可以在 chrome 中进行调试

实际使用中 reducer 应该以单独的文件存在,上面例子为了简单起见放到了一起。

useReducer虽然很好地分离了逻辑和 UI,但是无法像 redux 一样进行跨组件的状态共享,例如子组件无法方便的访问到num.

但 ueReducer 是可以性能优化。 dispatch 自带memorize(缓存),所以子组件不会进行重复的 re-render

useSelector、useDispatch

如上所述,Hooks 仍然无法替代 Redux 的作用,特别是在状态共享方面。庆幸的是 react-redux 7.1 之后也可以使用 useSelector、useDispatch 等 HooksApi 替代 connect,减少模板代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import React from "react";
import { createStore } from "redux";
import { Provider, useSelector, useDispatch } from "react-redux";

const initialState = { num: 0 };

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;
}
};

const store = createStore(reducer, initialState);

const ComponentUseReactRedux = () => {
return (
<div>
<h2>ComponentUseReactRedux</h2>
<Provider store={store}>
<ChildComponentUseReactRedux />
</Provider>
</div>
);
};

const ChildComponentUseReactRedux = () => {
const num = useSelector((state) => state.num);
const dispatch = useDispatch();
return (
<div>
<h3>Using useSelector, useDispatch</h3>
Number: {num}
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
</div>
);
};

export default ComponentUseReactRedux;

createStore

1
2
3
4
5
6
// 通过createStore将state存入store,
const store = createStore(reducer, initialState);
// 再通过Provider向子组件暴露store,通过store在父子组件之间共享状态
<Provider store={store}>
<ChildComponentUseReactRedux />
</Provider>;

useSelector

1
2
3
4
5
6
7
// 子组件可以通过useSelector访问state
const num = useSelector((state) => state.num);
// 当然,也可以提出selector函数,方便替换和复用,如下
const selector = (state) => {
return state.num;
};
const num = useSelector(selector);

useDispatch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 通过useDispatch 可以获取dispatch
const dispatch = useDispatch();
// 即使多几个子组件也可以共享状态
const ComponentUseReactRedux = () => {
return (
<div>
<h2>ComponentUseReactRedux</h2>
<Provider store={store}>
<ChildComponentUseReactRedux />
<ChildComponentUseReactRedux />
</Provider>
</div>
);
};

最后


通过 useSelector、useDispatch 等方法,我们可以用 Hooks 方法完成 Redux 的功能,Hooks 和 Redux 之间没有替代关系,应该更好地共存和融合。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!