Redux流程分析 传统流程和redux-toolkit的使用
Posted 我是真的不会前端
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redux流程分析 传统流程和redux-toolkit的使用相关的知识,希望对你有一定的参考价值。
redux官方给的两种库
传统Redux流程写法
react-redux
Redux框架主要由Action、Reducer和Store三大元素组成。
action
Action是一个普通对象,其中存在的type属性是必须的,用来表示Action的名称,type一般被定义为普通的字符串常量。为了方便管理,一般通过action creator来创建action,action creator是一个返回action的函数。
在Redux中,State的变化会导致View的变化,而State状态的改变是通过接触View来触发具体的Action动作的,根据View触发产生的Action动作的不同,就会产生不同的State结果。可以定义一个函数来生成不同的Action,这个函数就被称为action creator。
Reducer
当Store收到action以后,必须返回一个新的State才能触发View的变化,State计算的过程即被称为Reducer。Reducer本质上是一个函数,它接受Action和当前State作为参数,并返回一个新的State。
- 在子reducer中,一定要抛出一个reducer(实际上是一个由switch语句构成的函数)
Store
Store就是数据保存的地方,可以把它看成一个容器,整个应用中只能有一个Store。同时,Store还具有将Action和Reducers联系在一起的作用。Store具有以下的一些功能:
• 维持应用的 state;
• 提供getState()方法获取state;
• 提供dispatch(action)方法更新state;
• 通过subscribe(listener)注册监听器;
• 通过subscribe(listener)返回的函数注销监听器。
创建子store的方法
function reducer(initState,aciton)
流程(文字叙述)
createStore创建根store 一个store管理不同子store 合并子reducer使用方法combineReducers({}),使用applyMiddleware可以处理中间件.想要多个中间件就可以使用compose
reducer 其本质上可以写成swith case 语句.
根据不同的case分支来修改子store(action={type,payload}是信号,像一封邮件)
里面核心对原来state数据进行一次深复制 方法有很多种.
Object.assign jsonparse(jsonstringify)或者用immer等方法.
组件中 再app.jsx中安装react-redux库,使用<provider store></ provider>
全局注入store上下文
如果在react16.8以前 只能使用connect(mapstate,mapdispatch)(component),然后在props上就能访问这些store数据\\以及修改store的action的内部方法.
在16.8以后 更推荐useDispatch useSelector
异步问题
使用compose(applyMiddleWare(thunk), applyMiddleWare(logger))使用中间件,尤其是解决redux不支持异步action的问题。
import { createStore, combineReducers, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import logger from 'redux-logger'
export default createStore(
combineReducers({
test,
counter,
}),
// 当有多个中间件时
compose(applyMiddleware(thunk), applyMiddleware(logger))
)
建议封装的地方
type字典
例如这种
封装action生成器方法
@reduxjs/toolkit的流程
toolkit比较好的支持typestript
-
安装@reduxjs/toolkit这个库,使用configureStore({reducer,middleware})创建store。
-
createreducer创建初始值.其中参数是个build对象 .addcase就是你可以理解等同于添加case语句,每个case根据不同的action和不同的state 做不同事 抛出的reducer在store中使用
-
(1)name
命名空间,可以自动的把每一个action进行独立,解决了action的type出现同名的文件。在使用的时候默认会把使用name/actionName -
(2)initialState
state数据的初始值 -
(3)reducers
定义的action。由于内置了immutable插件,可以直接使用赋值的方式进行数据的改变,不需要每一次都返回一个新的state数据。
背后的深复制
createSlice方法创建一个slice。每一个slice里面包含了reducer和actions,可以实现模块化的封装。所有的相关操作都独立在一个文件中完成。
先看看源码 其是里面导入了immer
const testSlice = createSlice({
name:"tset" // 理解为命名空房间
initialState,
reducers:{} //里面放同步方法
extraReducers:(builder)=>{
builder.addCase('',(state,action)) //相当于添加了异步行为的switch语句,当达到状态后就执行回调,直接修改state.背后做了深复制操作
} //放置由createAsyncThunk创建的异步行为
})
.addCase('',(state))//链式语法回调函数
抛出举例
// 在子reducer中,一定要抛出一个reducer(实际上是一个由switch语句构成的函数)
export default userSlice.reducer // 给根store进行合并reducer
export { login, getUserInfo, addUser, getUserList, changeUserStatus } // 给业务逻辑用的
createslice方法实际上是对createReducer方法的封装,并且实际解决了immer的深复制过程
- 使用createSlice({name,initialState,reducers,extraReducers})创建子reducer,最后抛出子reducer给根store合并。
异步方法的添加
为啥能支持异步 先看看源码
背后其实还是用来thunk中间件
语法举例
const login:any = createAsyncThunk(
'user/login', // 其实就是action中的type(可以说是user子store中的login行为 写法不强制,但是讲究一点)
async (data) => { //异步行为 接收一个函数
const res:any = await fetchLogin(data) //等待异步行为的成功
console.log('登录成功', res)
localStorage.setItem('token', res.token)
return res.token // payload
}
)
使用该action
extraReducers: (builder)=>{
// 监听异步action成功,当异步action成功时,把结果直接更新到state上
builder
.addCase(login.fulfilled, (state:any, action)=>{ //只监听成功
console.log('---login', action)
state.token = action.payload
})
builder:可以理解为构建一个case
fulfilled表示fetch行为监听成功时的状态 在acition中拿到token
- 使用createAsyncThunk(‘user/login’, async (入参)=>(await fetchLogin())),给到createSlice.extraReducers中addCase添加异步成功状态,在成功状态中直接修改子store。这些由createAsyncThunk创建action方法,也要抛出,给React组件进行触发使用 dispatch(login(入参))。创建异步action
createAsyncThunk方法可以创建一个异步的action,这个方法被执行的时候会有三个( pending(进行中) fulfilled(成功) rejected(失败))状态。这可以监听状态的改变执行不同的操作。以下代码示例中使用到了extraReducers创建额外的action对数据获取的状态信息进行监听。
hooksAPI
在ts环境下要做一些小调整
在src文件下新建hook文件夹 下面添加index.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from '@/store'
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
对hooksAPI进行进出口处理
使用
- 在App中,安装react-redux,使用注入上下文。
- 在React组件中,只能使用 @reduxjs/toolkit官方推荐的 useAppSelector来使用store数据、只能使用useAppDispatch来触那些子store中抛出的action。
redux-toolkit是目前来说比较好的一个redux使用的解决方案,通过一些内置的插件和代码封装让redux的使用更加的方便顺手,而且条理更清晰。
create-react-app脚手架两种的区别
ES6环境(只能使用ES6语法、默认不支持TS,使用redux、react-redux)
定义redux时,参考store_backup代码
使用redux数据时,可以用connect、useSelector、useDispatch
create-react-app my-app1
TS环境(TS和ES6都可以使用、在这个环境使用redux、react-redux传统流程)
create-react-app my-app2 --template typescript
TS环境(只使用TS,不使用ES6,在这个环境中使用 @reduxjs/toolkit、react-redux)
create-react-app my-app3 --template redux-typescript
以上是关于Redux流程分析 传统流程和redux-toolkit的使用的主要内容,如果未能解决你的问题,请参考以下文章