美文网首页
redux 传统状态管理 vs redux tookit

redux 传统状态管理 vs redux tookit

作者: Riya | 来源:发表于2021-08-10 22:33 被阅读0次

Redux传统流程:

  • 安装redux,使用createStore(rootReducer、initState、middleWares)创建根store
  • 使用combineReducers({}) 合并多个子reducer
  • 使用compose(applyMiddleWare(thunk), applyMiddleWare(logger))使用中间件,尤其是解决redux不支持异步action的问题。
export default createStore(
  combineReducers({
    test,
    counter,
    cnode
  }),
  compose(applyMiddleWare(thunk), applyMiddleWare(logger))
)
  • 如何创建子reducer呢?function reducer(initState,aciton) {本质上是一堆switch语句},在编写子reducer时,核心逻辑是深复制(immer),根据不同的case分支来修改子store(action={type,payload}是信号,像一封邮件)
reducers -> counter.js
import produce from 'immer'
const initState = {
  num: 0
}
// reducer是纯函数, 不能修改入参
// 本质是由switch语句构成的函数 -> 深拷贝state,修改拷贝后的值,抛出(使用immer中间件做深复制)
export default function(state=initState, {type,payload}) {
//state -> 要深复制的值
// newState -> 深复制后的结果
  return produce(state, newState=>{
    switch (type) {
      case COUNTER_NUM_ADD:
// 修改深复制之后的结果
        newState.num += payload
        break
      case COUNTER_NUM_SUB:
        newState.num -= payload
        break;
      default:
    }
// 将修改后的结果抛出
    return newState
  })
}
reducers -> counter.js
import produce from 'immer'
import {
  GET_CNODE_LIST
} from '../types'

const initState = {
  list: []
}
export default function(state=initState, {type,payload}){
  return produce(state, newState=>{
    switch (type) {
      case GET_CNODE_LIST:
// 调接口后获得的数据
        console.log('cnode list', payload);
        newState.list = payload
        break
      default:
    }
    return newState
  })
}
  • 在App.jsx中,安装react-redux这个库,使用 ,React组件树中有了store上下文。
  • 在React组件中,如果是16.8以前,只能使用 connect(mapState, mapDispatch)(Component),然后在props上就能访问这些store数据、以及那些修改store的action逻辑。
//类组件写法,使用修饰符@
import React from "react";

import { connect } from ".react-redux";
import { updateMsg } from '@/store/actions'

function mapStateToProps({test}) {
  return {
    msg: test.msg
  }
}
function mapDispatchToProps(dispatch) {
  return {
    updateMsg: payload => dispatch(updateMsg(payload))
  }
}
// mapStateToProps 映射state放到props上
// mapDispatchToProps 映射dispath放到props上
@connect(mapStateToProps, mapDispatchToProps)
class PanelA extends React.Component {
  updateMsg() {
    this.props.updateMsg(Math.random())
  }
  render() {
    console.log('PanelA 类组件的props', this.props);
    return (
      <div>
        <h1>在类组件中使用Redux数据</h1>
        <h1>{this.props.msg}</h1>
        <button onClick={()=>this.updateMsg()}>change MSG</button>
      </div>
    )
  }
}
export default PanelA
//函数式组件写法
import React from 'react'
import { connect } from 'react-redux'
import { updateMsg } from '@/store/actions'

export default connect(
  ({test})=>({
    msg: test.msg
  }),
  dispatch=>({
    // updateMsg(payload)返回一个action
    updateMsg: payload=>dispatch(updateMsg(payload))
  })
)(props => {
    return (
    <div>
      <h1>在函数式组件中使用redux数据</h1>
      <h1>{props.msg}</h1>
      <button onClick={()=>props.updateMsg('hello 朱晓玥')}>修改msg</button>
    </div>
  )
  }
)
  • 在React组件中,如果是16.8以后,除了connect可以用,建议使用更好的 useDispatch、useSelector。
// 标准做法 hooks写法
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { updateMsg } from '@/store/actions'
export default () => {
  const msg = useSelector(({test})=>test.msg)
  const dispatch = useDispatch()
  return (
    <div>
      <h1>在函数式组件中使用redux数据</h1>
      <h1>{msg}</h1>
      <button onClick={()=>dispatch(updateMsg(Math.random()))}>修改msg</button>
    </div>
  )
}
  • 在传统的redux架构中,为了让action更好地维护和复用,我们一般建议封装action生成器方法。
import {
  COUNTER_NUM_ADD,
  COUNTER_NUM_SUB,
} from '../types'
import { fetchCnode } from '@/api'
// 返回整体action type+payload
// action生成器(creator)
export function addNum(payload) {
  return {
    type: COUNTER_NUM_ADD,
    payload
  } 
}
export function subNum(payload) {
  return {
    type: COUNTER_NUM_SUB,
    payload
  } 
}
// 使用thunk插件
// 调接口结束后再触发dispatch方法,将调接口获取到的值,传到reducer中,更新状态管理中的数据
export function getList(payload) {
  return dispatch => {
    // 调接口
问题:
在这里有一个坑,这里只是获得了调接口后的数据,但是还没有改变状态管理中的数据
初始化时,在视图中dispatch(fetchCnode(values)),接着在后面使用状态管理中调接口获取到的数据
会是undefined,这时候很可能状态管理还没有运行到改变数据时,视图就已经更新
解决方法:
在状态管理中设置一个标记success,初始值为false,状态管理中数据更新后,同时将success改为true
在视图中判断数据是否在状态管理中更新,使用success判断即可

    fetchCnode(payload).then(list=>{
      console.log('actions list data', list);
      dispatch({
        type: GET_CNODE_LIST,
        payload: list
      })
    })
  }
}
  • 在传统的redux架构中,为了避免协同开发时大家滥用type或者type冲突,我们一般建议封装一个type字典。
// actions type 的字典,视图中和reducer中使用
export  const COUNTER_NUM_ADD = 'COUNTER_NUM_ADD'
export  const COUNTER_NUM_SUB = 'COUNTER_NUM_SUB'
export  const GET_CNODE_LIST = 'GET_CNODE_LIST  '

redux tookit

  • 安装@reduxjs/toolkit这个库,使用configureStore({reducer,middleware})创建store。
import thunk from 'redux-thunk'
import login from './reducer/login'
import { configureStore } from '@reduxjs/toolkit'
import logger from 'redux-logger'
export const store = configureStore({  
  reducer: {
    login
  },
// 不要直接写数组,否则会把toolkit中封装的默认middleware覆盖
// 可以不加thunk,redux-toolkit默认安装了thunk
  middleware: getDefaultMiddleware => [...getDefaultMiddleware(), thunk, logger ]
})

export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch

export default store
  • 使用createSlice({name,initialState,reducers,extraReducers})创建子reducer,最后抛出子reducer给根store合并。
export const loginSlice = createSlice({
  name: 'login',
  initialState: {
    token : localStorage.getItem('token'),
    user: { },
    success: false,
    color: ''
  },
// 同步reducer(不需要调接口的reducer)
  reducers: {
    addColor(state, action) {
      console.log(action.payload,'addcolor-----')
      state.cardColor = action.payload
    }
  },
// toolkit封装,将同步reducer变为异步reducer
  extraReducers: (builder) => {
    builder.addCase (login.fulfilled, (state, action)=>{
      // 直接修改state(tookit中封装了immer,在内部已经做过深复制了)
      console.log('----login', action);
      state.token = action.payload
    })
// fulfilled 表示调接口成功的状态,总共有三种状态
    .addCase(getUserInfo.fulfilled, (state, action)=>{
      state.user = action.payload
    })
    // .addCase(...)
  }
})
// 在子reducer中,一定要抛出一个reducer(实际上是一个由switch构成的函数)
export default loginSlice.reducer
// 抛出异步reducer
export { getUserInfo }
// 抛出同步reducer
export const { addColor } = cardSlice.actions
  • 使用createAsyncThunk('user/login', async (入参)=>(await fetchLogin())),给到createSlice.extraReducers中addCase添加异步成功状态,在成功状态中直接修改子store。这些由createAsyncThunk创建action方法,也要抛出,给React组件进行触发使用 dispatch(login(入参))。
// 在视图中通过dispatch(login(params))
// 成功时,执行对应的case,并修改state,更新视图
const login = createAsyncThunk(
  // 信号
  'login/tologin', //type
  // 函数(action)
  async (data) => {
    const res = await loginApi(data)
    const token = res.token
    localStorage.setItem('token', token)
    return token  //payload
  }
)
const getUserInfo = createAsyncThunk(
  'login/getUserInfo', //type
  async (params) => {
    const res = await getUserInfoApi(params)
    return res  //payload
  }
)
  • 在App中,安装react-redux,使用注入上下文。
import { Provider } from 'react-redux'
function App() {
  return (
    <Provider store={store}>
      <DashBoard />
    </Provider>
  )
}
export default App;
  • 在React组件中,只能使用 @reduxjs/toolkit官方推荐的 useAppSelector来使用store数据、只能使用useAppDispatch来触那些子store中抛出的action。
import { useAppSelector, useAppDispatch } from '@/hooks'
export default () => {
  const dispatch = useAppDispatch()
  const token = useAppSelector(({login})=>login.token)
  useEffect(()=>{
    if(token) {
      dispatch(getUserInfo(token))
    }
  },[token])
}

ps:需要自己封装hooks

import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from '@/store'

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector

相关文章

  • redux 传统状态管理 vs redux tookit

    Redux传统流程: 安装redux,使用createStore(rootReducer、initState、mi...

  • Redux

    Redux状态管理 Redux 是 JavaScript 状态管理容器,提供可预测的状态管理。redux 可以让你...

  • 从零开始撸一个Redux

    Redux Redux 属于视图状态管理工具,它解决了传统 MVVM 架构的 VM 层状态管理责任过重的问题,他使...

  • React实战之Redux

    Redux、React-Redux 简介 Redux 是 JavaScript 状态容器,提供可预测化的状态管理。...

  • react-redux

    redux 全局状态管理 react-redux 优化模块 优化redux的使用过程 通过react-redux ...

  • SwiftUI 中使用 Redux 设计模式

    什么是Redux ?Redux 是 JavaScript 状态容器,提供可预测化的状态管理 Redux的工作原理 ...

  • redux

    Redux Redux 是JavaScript状态的容器,提供可预测化的状态管理 Redux不是React必须的,...

  • redux 浅析

    什么是 Redux Redux 是 JavaScript 状态容器,提供可预测化的状态管理。 Redux 是如何工...

  • Redux详解

    Redux是什么 Redux 是 JavaScript 状态容器,提供可预测化的状态管理。 什么场景使用Redux...

  • Redux 分析

    Redux 是什么 Redux 是 Javascript 状态容器,提供可预测化的状态管理 Redux的功能及作用...

网友评论

      本文标题:redux 传统状态管理 vs redux tookit

      本文链接:https://www.haomeiwen.com/subject/iwifbltx.html