最近是看到有同事在更新项目的redux,才知道redux官方更新了一些东西,这个redux-toolkit就是这个更新的最大变化。那它有啥变化呢?那我们就拿以往的redux以及react-redux、redux-thunk等等一些,做一个小比较就知道了。
这里附上它的官方:https://redux-toolkit.js.org
github: https://github.com/reduxjs/redux-toolkit
可以先来个新旧对比
我们以前配置redux,一般都是结合redux-thunk,react-redux已经其他的一些redux-saga等等之类的,例如
store/index.js
import { createStore, compose, applyMiddleware } from "redux"
import thunk from "redux-thunk"
import reducer from "./Modules"
// 浏览器的redux调试插件挂载
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
//中间件
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))
export default store
store/Modles/index.js
import { combineReducers } from "redux"
import User from "./UserModule/reducer"
import FormModule from "./FormModule/reducer"
//多个reducer
export default combineReducers({
User,
FormModule
})
一般来说,我们每个reducer都会有四个js文件,action(通知去操作)、reducer(操作)、state(值)、types(每个通知的名称),这里简单的说一个这几个文件的含义。
在最开始的入口文件
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { store } from './store' //上面的store/index.js
import { Provider } from 'react-redux'
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<Provider store={store}> //包裹着App.js
<App />
</Provider>
)
在某个组件使用它的时候(旧的react-redux方法)
后面我会把新的react-redux的(通知)方法再说一遍,这里先讲旧的
import React, {memo} from "react"
import { connect } from "react-redux"
import {UpdateForm} from "./store/Modules/FormModule/action" //上面的FormModule里面的action
function FormPanel (porps) {
const {formConfig} = porps //这里是state里面的一个值
//然后你就在下面使用,具体怎么就看你个人了,我这里简单写一下
const ToDo = ()=>{
UpdateForm("111) //传递111过去修改formConfig里面的值
}
<div>
<button Onclick = { ()=>ToDo() }>点一下</button>
<div> {formConfig.text}</div> //假如UpdateForm是修改formConfig.text的值,那上面的点击事件点击一下,这里也会相对应的改变
</div>
}
//这下面就是用一个高阶组件的形式,connect是react-redux提供的
export default connect((state) => ({
formConfig: state.FormModule.formConfig //state里面的值
}), {
UpdateForm //action(通知)
})(memo(FormPanel)) //memo缓存
新的@redux-toolkit
store/index.js
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './Modules/counterReducer'
import UserModule from "./Modules/UserModule"
// redux-saga
export const store = configureStore({
//多个reducer
reducer: {
counter: counterReducer,
User: UserModule
},
middleware: getDefaultMiddleware => getDefaultMiddleware({
thunk: true
}) //这里的middleware把redux-thunk中间价包含在里面了,还有另外两个中间价 immutableCheck、serializableCheck;
//如果你还想内置其他的中间价可以在这后面加上.concat(”中间价名称“)
})
middleware是@reduxjs/toolkit用于管理中间价的,里面包含了thunk、immutableCheck、serializableCheck这三个中间件
counterReducer/index.js
import { createSlice } from '@reduxjs/toolkit'
import { increment as inc, decrement as dec } from './add' //操作action的方法reducer
//initialState相当于state,这里也可以分离出去,模块化
const initialState = {
value: 0
}
export const counterSlice = createSlice({
name: 'counterReducer', //对应上面的多个reducer,其实就是个名字
initialState, //initialState相当于state
//这里我做了模块化处理
reducers: {
increment: inc,
//相对于
/*
increment: (state) => {
state.value += 1
}
*/
decrement: dec,
}
})
//这些就是以前的action
export const { increment, decrement} = counterSlice.actions
//那这个就是reducer(操作数据)
export default counterSlice.reducer
具体使用
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { decrement, increment } from '../store/Modules/counterReducer' //相于counterReducer里面的action(通知)
// decrement() 打印出来相当于一个对象 { payload:"",type:"相当于你那边的name/decrement",}
export default function test () {
//这里的值对应counter当中的initialState的value值
const count = useSelector((state) => state.counter.value)
const dispatch = useDispatch()//通知
return (
<div>
<div>test</div>
<div>
<button onClick={() => dispatch(decrement())}>点击-1</button> //和下面的写法是一样的
<button onClick={() => dispatch({payload:"111",type:"counterReducer/increment "})}>点击+1</button>
</div>
<div>{count}</div>
</div>
)
}
这里的useSelector, useDispatch是react-redux新的一个用法,可能也不算新了,哈哈。
反正就是不再像以前使用高阶函数那样子去做了,而是可以直接这样子去使用,非常方便!
createAsyncThunk
我们可以再来看看 createAsyncThunk 这个语法,这也是@reduxjs/toolkit的一个产物,用于异步操作处理的,我也是简单的用了一下,先附上官网它的一系列用法,挺多的,就看你具体怎么使用了。https://redux-toolkit.js.org/usage/usage-guide#async-requests-with-createasyncthu
user.js
也就是上面的多个reducer中的UserModule
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import { getNews } from '@http/api/News'
//initialState就是state,命名不能改的
const initialState = {
value: 0,
arr: []
}
//暴露出UserById
export const UserById = createAsyncThunk(
'userModel/userByIdStatus', //这里理解为给个命名就好了
async (Id, { rejectWithValue }) => {
try {
const response = await getNews({ id: Id } Id }) //这里的getNews是我二)
console.log(response)
return response.data
} catch (err) {
//接收失败返回
return rejectWithValue(err.response.data)
}
}
)
export const UserSlice = createSlice({
name: 'userModel',
initialState,
reducers: {
//这里我们没有其他的action和reducer
},
// extraReducers这里用来处理那些异步操作,走完UserById ,还会走这里
extraReducers: (builder) => {
/*builder.addCase是内置的一个方法,UserById.fulfilled对应UserById成功返回的数据
也有失败返回,是正在准备的返回,有三个属性,详细可以去看官网*/
builder.addCase(UserById.fulfilled, (state, action) => {
state.arr.push(action.payload) //payload里面就是接口返回的值
})
}
})
export default UserSlice.reducer
具体用法和上面的差不多,就是dispath(UserById(“传个值”)), useSelector((state) => state.userModel.arr)
需要注意的是:
initialState命名不能变- 走完
UserById后,会走extraReducers,builder.addCase是内置的一个方法,里面可以接收每一个createAsyncThunk的返回状态,其中有三种状态,正在准备中,成功,失败