先上官方写法
import { createSlice} from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
incremented: state => {
// Redux Toolkit allows us to write "mutating" logic in reducers. It
// doesn't actually mutate the state because it uses the Immer library,
// which detects changes to a "draft state" and produces a brand new
// immutable state based off those changes
state.value += 1
},
decremented: state => {
state.value -= 1
}
}
})
传统的redux需要将action,reducer分别进行封装,使用起来较为繁琐,在reduxjs/toolkit中action和reducer合为一体,和vue中状态管理工具pinia较为相似。
对象中属性initialState和传统reducer第一个参数preState作用一致,皆为默认的状态。
reducers中incremented对应传统action的type,参数state为更改前的状态,即reducer还没有被触发之前的上一次状态。
注意:在reducer中执行的操作为state对象属性value的直接修改,并且没有返回值,不符合纯函数的原则,说明reducer可以不是纯函数,原因会在后面进行讲解
稍微修改上面的例子:
const counterSlice = createSlice({
name: 'counter',
initialState: 0,
reducers: {
incremented: state => {
//state += 1 //错误写法
return state + 1
},
decremented: state => {
return state - 1
}
}
})
此处遵循了纯函数的原则,与原来的reducer写法相似。
再看一个对象的例子:
const peopleSlice = createSlice({
name: 'people',
initialState: [
{
name: "zhangsan"
}
],
reducers: {
//{payload}为解构赋值,获取参数里面的payload,payload为dispatch传过来的参数
addPeople: (state, {payload}) => {
console.log(payload)
//return [payload, ...state]//纯函数写法
state.push(payload)
}
}
})
此处第二个参数为提交reducer时传递的参数,使用解构单独拿了出来。此处可以使用两种写法,一种是原来的纯函数写法,利用解构将参数赋给一个新对象并且返回:return [payload, …state],另一种是直接修改原来的state:state.push(payload),在文章第一个例子中也可以使用纯函数写法,如: return {value: state.value + 1}
在接上面的讲解之前需要先明白一个概念,javascript中基本数据类型值不可变,变量重新赋值实际上是在内存中新建了一个值,将这个变量名指向了新建的值的地址。引用数据类型其值是可变的,对其值的修改就是在原始内存地址上面做修改。
知道上面的概念后开始讲解。其实是reduxjs/toolkit作者进行的解释:
Immer requires that you either return an entirely new state value, or mutate the existing state.
意思就是reducer需要你返回一个新的状态或者修改现有状态的值
在第二个例子中,如果直接写state += 1会修改state指向新的值,不符合原则,为错误写法。
而第三个例子中可以直接修改对象属性是因为修改对象属性并不会修改对象的地址值。
封装store由redux的createStore改为configureStore,多个reducer不使用combineReducers而是使用configureStore对象属性reducer,如下:
export const store = configureStore({
reducer:{
counter: counterSlice.reducer,
people: peopleSlice.reducer
}
})
之后和redux一样,用
包裹
组件实现状态全局共享。(记得引入configureStore在reduxjs/toolkit中)
先在上面的reduxjs/toolkit配置中导出action,语法为:
export const {incremented, decremented} = counterSlice.actions
export const {addPeople} = peopleSlice.actions
在ui组件界面引入需要的hook以及需要使用的action:
import {useDispatch, useSelector} from "react-redux";
import {incremented,addPeople} from "../ToolKitTest";
useSelector为查看状态,useDispatch为修改状态
使用hook的方式为:
//解构赋值获取store中state
//counter,people都为上面封装store对象的reducer属性的键的名字,此处获取后为state的值
const {counter,people }= useSelector(state=>state)
//获取store中dispatch
const dispatch = useDispatch()
获取的counter和people使用方法为:
{/*遍历获取people对象的内容*/}
{people.map(item=>{
return <p key={item.name}>{item.name}</p>
})}
{/*counter为对象,获取它的value*/}
<p>{counter.value}</p>
dispatch使用方法为:
//dispatch调用action,参数为传给action的参数,即上文形参的{payload}
dispatch(addPeople({name:"ls"}))