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) => {
return 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
的经验文章,请点击:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。