create-react-app的redux范例,如何通过dispatch修改state?
发布于 作者:苏南大叔 来源:程序如此灵动~
本文接着分析create-react-app的redux范例,reducer整合到了redux/toolkit的slice内。本文则侧重于这些函数如何调用,也就是dispatch的概念。react-redux提供了个useDispatch()的概念,就是用来干这个事情的。

大家好,这里是苏南大叔的程序如此灵动博客,这里记录苏南大叔的代码故事。本文描述react和redux结合后,如何调用定义在reducer里面的函数修改state的故事。测试环境:win10,node@16.14.2,create-react-app@5.0.1,reduxjs/toolkit@1.8.3,react-redux@8.0.2。
useSelector读取只读state
react-redux中使用useState()来获得redux中的state的数据,并且相关函数里面是无法修改state的数据的,会提示无法扩展或者只读。相关文章:
const selectCount = (state) => state.store_reducer_name.value;
const count = useSelector(selectCount);翻译过来是这样的:
const count = state.store_reducer_name.value;reducer修改state
想修改state中的数据,使用的概念是定义在slice中的reducers里面函数,修改state数据。
export const counterSlice = createSlice({
name: 'counter_slice_name',
initialState :{
value: 0,
status: 'idle',
},
reducers: {
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action) => {
state.value += action.payload;
},
},
});
这里的核心范例代码,如下:
decrement: (state) => {
state.value -= 1;
},incrementByAmount: (state, action) => {
state.value += action.payload;
},重点就是action.payload,就是传递过来的参数,可以是任何类型。比如:数组、字符串、数字、object等。
dispatch执行reducer转变的action
这里首先有个useDispatch,来自react-redux。使用了之后,就可以在react组件里面调用相关的reducer函数了。
范例如下:src/view/counter.js:
import { useDispatch } from 'react-redux';
import {
decrement,
// increment,
incrementByAmount,
// incrementAsync,
// incrementIfOdd,
// selectCount,
} from './../logic/slice';
export function Counter() {
const dispatch = useDispatch();
return (
<div>
<button
className={styles.button}
aria-label="Decrement value"
onClick={() => dispatch(decrement())}
>-</button>
<button
className={styles.button}
aria-label="Increment value"
onClick={() => dispatch(incrementByAmount(2)}
>+</button>
</div>
)
}
核心代码:
import { useDispatch } from 'react-redux';
const dispatch = useDispatch();
// dispatch(decrement())
// dispatch(incrementByAmount(2))特例reducer的写法
slice.js中定义了一个游离在createSlice()外部的reducer,叫做incrementIfOdd():
export const selectCount = (state) => state.store_reducer_name.value;
// export const getState = (state) => state.store_reducer_name;
export const incrementIfOdd = (amount) => (dispatch, getState) => {
const currentValue = selectCount(getState());
if (currentValue % 2 === 1) {
dispatch(incrementByAmount(amount));
}
};
特殊点一:函数incrementIfOdd()
- 拥有两个
=>,苏南大叔目前认为:可能是后面的()=>{}返回了一个{},然后和第一个()=>做了个组合。 - 局部变量
dispatch和getState,代表两个函数。其中dispatch的用法和上一节中说的一样。getState和想象中的一样。因为是局部变量,和全局自定义的getState()没有关系。
特殊点二:函数selectCount()
这是个获得state的函数,在这个例子里面,结论是:要看使用函数的调用位置,来决定使用的方式。
- 使用方式并不是
const currentValue = useSelector(selectCount)。 - 而是常规的
const currentValue = selectCount(getState())。
特殊点三:函数incrementIfOdd()调用方式
这个定义在slice之外的action,调用方式和定义在slice之内的action是一样的。
onClick={() => dispatch(incrementByAmount(2))}
onClick={() => dispatch(incrementIfOdd(2))}特殊点四:函数incrementIfOdd()的type
incrementIfOdd()没有定义在reducers里面,没有type,不会留痕,无法回访。- 内部有条件地调用了
dispatch(incrementByAmount(amount)),只有调用的时候,才会留痕支持回访。而且回放的也是incrementByAmount,无法体现incrementIfOdd的存在。
特殊点五:对于incrementIfOdd()来说,有两个dispatch
- 外部调用一个,
onClick={() => dispatch(incrementIfOdd(incrementValue))}。 - 内部调用一个,而且还是个局部变量
(dispatch, getState) => {}。
关于action.type
其实每个被dispatch的函数,都有个type。这些没有被显示定义type的,都会被自动生成一个名字。规则就是:slice的名字+函数的名字。下面的是redux-devtools的相关截图:

至于这个叫做reducer还是叫做action,确实有些混乱。苏南大叔是这么理解的:
- 定义的时候,这个就叫做
reducer。 - 被
slice加工过的reducer,或者说被dispatch调用的,就叫做action。
相关文档
- https://newsn.net/say/react.html
- https://newsn.net/say/redux.html
- https://newsn.net/say/react-usestate.html
- https://newsn.net/say/redux-useselector.html
综述
更多redux的经验文章,请点击: