• React 状态管理 - Redux 进阶(下)提升开发体验


    目录

    扩展学习资料

    Reselect【数据持久化】&Immutable Data【不变数据】方案【解决某些场景重复渲染,重复计算的问题】

    @/src/reducer/index.js

    Reselect【 可缓存的筛选项,当数据量大的时候,可以节省diff时间,提升渲染效率】

    @src/reducer/reselect/index.js

    @/src/actions/reselect/index.js

    @/src/containers\reselect\index.jsx

     @/src/store/index.js

    Immutable Data

    Immutable方案

    @/src/containers/immutable/index.jsx

     @/src/actions/immutable/index.js

    @/src/reducer/immutable/index.js

    redux-actions & @rematch/core & dva【比较高阶状态管理方案】

    @/src/actions/redux-actions/index.js

    @/src/containers/redux-actions/index.jsx

    @/src/reducer/redux-actions/index.js

    Reudx的不足

    redux-actions & @rematch/core & dva


    扩展学习资料

    名称

    链接

    备注

    redux-actions

    Introduction - redux-actions

    英文

    @rematch/core

    Rematch | Rematch

    dva

    介绍 | DvaJS

    Reselect【数据持久化】&Immutable Data【不变数据】方案【解决某些场景重复渲染,重复计算的问题】

    @/src/reducer/index.js
    1. import { combineReducers } from 'redux';
    2. import homeReducer from './home';
    3. import reSelectReducer from './reselect';
    4. import immutableReducer from './immutable';
    5. import reduxActionsReducer from './redux-actions';
    6. // console.log(reSelectReducer());
    7. // 合并多个reducer
    8. // 扩展性
    9. export default combineReducers({
    10.   homeReducer,
    11.   reSelectReducer,
    12.   immutableReducer,
    13.   reduxActionsReducer,
    14. });

    Reselect【 可缓存的筛选项,当数据量大的时候,可以节省diff时间,提升渲染效率】

    • 针对mapStateToProps中state在同一数据源中需要筛选的场景
    • mapStateToProps中state如果带有筛选函数,会导致每次返回新对象
    @src/reducer/reselect/index.js
    1. import * as types from '@/actions/mutation-types';
    2. const initialState = {
    3.   reSelectList: [{
    4.     key: '001',
    5.     status: true,
    6.     name: 'flex-reselect-1',
    7.   }, {
    8.     key: '002',
    9.     status: true,
    10.     name: 'flex-reselect-2',
    11.   }, {
    12.     key: '003',
    13.     status: false,
    14.     name: 'flex-reselect-3',
    15.   }, {
    16.     key: '004',
    17.     status: true,
    18.     name: 'flex-reselect-4',
    19.   }, {
    20.     key: '005',
    21.     status: false,
    22.     name: 'flex-reselect-5',
    23.   }, {
    24.     key: '006',
    25.     status: false,
    26.     name: 'flex-reselect-6',
    27.   }, {
    28.     key: '007',
    29.     status: true,
    30.     name: 'flex-reselect-7',
    31.   }],
    32.   filterStatus: 'FILTER_ALL_DATA',
    33. };
    34. const mutations = {
    35.   [types.FILTER_ALL_DATA](state) {
    36.     return { ...state };
    37.   },
    38.   [types.UPDATE_FILTER_STATUS](state, action) {
    39.     return {
    40.       ...state,
    41.       filterStatus: action.payload,
    42.     };
    43.   },
    44. };
    45. export default function (state = initialState, action) {
    46.   if (!mutations[action.type]) return state;
    47.   return mutations[action.type](state, action);
    48. }
    @/src/actions/reselect/index.js
    1. import * as types from '../mutation-types';
    2. export function filterData(data, filter) {
    3.   console.log(filter, 'filter', Date.now());
    4.   switch (filter) {
    5.   case types.FILTER_ALL_DATA:
    6.     return data;
    7.   case types.FILTER_SUCCESS_STATUS:
    8.     return data.filter(item => item.status);
    9.   case types.FILTER_FAIL_STATUS:
    10.     return data.filter(item => !item.status);
    11.   default:
    12.     return data;
    13.   }
    14. }
    15. export function updateFilterStatus(params) {
    16.   return {
    17.     type: types.UPDATE_FILTER_STATUS,
    18.     payload: params,
    19.   };
    20. }
    @/src/containers\reselect\index.jsx
    1. import React, { Component } from 'react';
    2. import propTypes from 'prop-types';
    3. import { connect } from 'react-redux';
    4. // 可缓存的筛选项,当数据量大的时候,可以节省diff时间,提升渲染效率
    5. import { createSelector } from 'reselect';
    6. import {
    7.   filterData,
    8.   updateFilterStatus,
    9. } from '@/actions/reselect';
    10. const filterStatusMap = {
    11.   1: 'FILTER_ALL_DATA',
    12.   2: 'FILTER_SUCCESS_STATUS',
    13.   3: 'FILTER_FAIL_STATUS',
    14. };
    15. const getReselectList = (state) => state.reSelectReducer.reSelectList;
    16. const getFilterStatus = (state) => state.reSelectReducer.filterStatus;
    17. // 一个可以缓存的数据源,避免了数据的重复计算,和页面更新
    18. const filterReselectData = createSelector(
    19.   [getReselectList, getFilterStatus],
    20.   (list, filter) => filterData(list, filter),
    21. );
    22. // filterData(
    23. //   state.reSelectReducer.reSelectList,
    24. //   state.reSelectReducer.filterStatus,
    25. // )
    26. @connect(
    27.   (state) => ({
    28.     filterList: filterReselectData(state),
    29.   }),
    30.   (dispatch) => ({
    31.     updateFilterStatus: (params) => dispatch(updateFilterStatus(params)),
    32.   }),
    33. )
    34. export default class ReselectDemo extends Component {
    35.   handleUpdate = (signal) => {
    36.     const { updateFilterStatus } = this.props;
    37.     updateFilterStatus(filterStatusMap[signal]);
    38.     // console.log(signal, this.props, updateFilterStatus);
    39.   }
    40.   render() {
    41.     const { filterList } = this.props;
    42.     return (
    43.       <div>
    44.         <>
    45.           {filterList.map(item => (
    46.             <div key={item.key}>
    47.               <span>{item.name}span>
    48.                 
    49.               <span>{String(item.status)}span>
    50.             div>
    51.           ))}
    52.        
    53.         <button type="button" onClick={() => this.handleUpdate(1)}>全部button>
    54.         <button type="button" onClick={() => this.handleUpdate(2)}>成功button>
    55.         <button type="button" onClick={() => this.handleUpdate(3)}>失败button>
    56.      
  •     );
  •   }
  • }
  • ReselectDemo.propTypes = {
  •   filterList: propTypes.arrayOf(propTypes.object),
  •   updateFilterStatus: propTypes.func,
  • };
  • ReselectDemo.defaultProps = {
  •   filterList: [],
  •   updateFilterStatus: () => null,
  • };
  •  @/src/store/index.js
    1. import { createStore, applyMiddleware, compose } from 'redux';
    2. import thunk from 'redux-thunk';
    3. import reducers from '@/reducer';
    4. const middlewares = [thunk];
    5. // 配合浏览器安装的redux开发者工具
    6. const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
    7. export default createStore(
    8.   reducers,
    9.   composeEnhancers(applyMiddleware(...middlewares)),
    10. );

    Immutable Data

    • 避免副作用
    • 状态可追溯
    • React中比较是shallowCompare【浅比较,判断是否重绘】

    Immutable方案

    immutable.js

    • 提供完整的API,与普通的JS对象不同,两者不能直接使用
    • 对Redux的应用程序来说,整个state tree应该是Immutable.JS对象,根本不需要使用普通的JavaScript对象

    immer.js【让状态可追溯、避免副作用、纯函数,大型项目必备,避免一些不必要的问题:健壮性,维护问题】

    • JS原生数据结构实现的immutable也提供了一套应对的API,相比immutable更推荐使用
    @/src/containers/immutable/index.jsx
    1. import React, { Component } from 'react';
    2. import { connect } from 'react-redux';
    3. import propTypes from 'prop-types';
    4. import updateImmutableData from '@/actions/immutable';
    5. @connect(
    6.   (state) => {
    7.     console.log(state.immutableReducer);
    8.     return ({
    9.       complexData: state.immutableReducer.complexData,
    10.     });
    11.   },
    12.   (dispatch) => ({
    13.     updateImmutableData: (params) => dispatch(updateImmutableData(params)),
    14.   }),
    15. )
    16. export default class ImmutableDemo extends Component {
    17.   handleClick = () => {
    18.     const { updateImmutableData } = this.props;
    19.     updateImmutableData('immutable 云');
    20.   }
    21.   render() {
    22.     const { complexData } = this.props;
    23.     return (
    24.       <div>
    25.         <div>
    26.           {complexData?.commonInfo?.name?.firstName}
    27.         div>
    28.         <button type="button" onClick={this.handleClick}>更改button>
    29.       div>
    30.     );
    31.   }
    32. }
    33. ImmutableDemo.propTypes = {
    34.   complexData: propTypes.objectOf(propTypes.object),
    35.   updateImmutableData: propTypes.func,
    36. };
    37. ImmutableDemo.defaultProps = {
    38.   complexData: {},
    39.   updateImmutableData: () => null,
    40. };
     @/src/actions/immutable/index.js
    1. import * as types from '../mutation-types';
    2. export default function updateImmutableData(params) {
    3.   return {
    4.     type: types.UPDATE_IMMUTABLE_DATA,
    5.     payload: params,
    6.   };
    7. }
    @/src/reducer/immutable/index.js
    1. import produce from 'immer';
    2. import * as types from '@/actions/mutation-types';
    3. const initialState = {
    4.   complexData: {
    5.     commonInfo: {
    6.       name: {
    7.         firstName: '云',
    8.         secondName: 'Fedora',
    9.       },
    10.     },
    11.     specialInfo: {
    12.       address: '网商路24599号',
    13.     },
    14.   },
    15. };
    16. const mutations = {
    17.   [types.UPDATE_IMMUTABLE_DATA](state, action) {
    18.     return produce(state, draftState => {
    19.       // eslint-disable-next-line no-param-reassign
    20.       draftState.complexData.commonInfo.name.firstName = action.payload;
    21.       console.log('oldState', state);
    22.     });
    23.     // const { complexData } = state;
    24.     // const newComplexData = { ...complexData };
    25.     // newComplexData.commonInfo.name.firstName = action.payload;
    26. // 改变了源,产生了副作用,无法回溯
    27.     // console.log('newComplexData Vs complexData', newComplexData, complexData);
    28.     // return {
    29.     //   ...state,
    30.     //   complexData: newComplexData,
    31.     // };
    32.   },
    33. };
    34. export default function (state = initialState, action) {
    35.   if (!mutations[action.type]) return state;
    36.   return mutations[action.type](state, action);
    37. }

    redux-actions & @rematch/core & dva【比较高阶状态管理方案】

    Redux扩展&更多状态管理方案

    @/src/actions/redux-actions/index.js
    1. import * as types from '../mutation-types';
    2. export default function updateReduxActions(params) {
    3.   return {
    4.     type: types.UPDATE_REDUX_ACTIONS_DATA,
    5.     payload: params,
    6.   };
    7. }
    @/src/containers/redux-actions/index.jsx
    1. import React, { Component } from 'react';
    2. import { connect } from 'react-redux';
    3. import propTypes from 'prop-types';
    4. @connect((state) => state.reduxActionsReducer)
    5. export default class ReduxActionsDemo extends Component {
    6.   render() {
    7.     const { actionName } = this.props;
    8.     return (
    9.       <div>
    10.         {actionName}
    11.       div>
    12.     );
    13.   }
    14. }
    15. ReduxActionsDemo.propTypes = {
    16.   actionName: propTypes.string,
    17. };
    18. ReduxActionsDemo.defaultProps = {
    19.   actionName: '',
    20. };
    @/src/reducer/redux-actions/index.js
    1. import * as types from '@/actions/mutation-types';
    2. const initialState = {
    3.   actionName: '云',
    4. };
    5. const mutations = {
    6.   [types.UPDATE_REDUX_ACTIONS_DATA](state, action) {
    7.     return {
    8.       ...state,
    9.       actionName: action.payload,
    10.     };
    11.   },
    12. };
    13. export default function (state = initialState, action) {
    14.   if (!mutations[action.type]) return state;
    15.   return mutations[action.type](state, action);
    16. }

    Reudx的不足

    • Redux范式繁琐 完成一次页面渲染,需要在Action层分别定义type,Action方法,Reducer中响应Action方法。完成一次流程需要在多个文件夹中来回切换
    • 基础功能匮乏 默认只有同步方法,异步数据请求需要安装插件(redux-thunk),复杂功能交由第三方插件完成,有一定的接入成本。

    redux-actions & @rematch/core & dva

    • 三种解决方案的对比:都解决了多层范式【写一个redux要改好多文件夹里的文件】

    旧的react项目redux解决多层范式问题建议使用redux-actions;e

    新的react项目建议使用dva或@rematch/core是比较成熟的框架;有中文文档

    选择技术方案的着重点:

    1.接入成本:学习的曲线

    2.改造成本:使用后,团队的是否接受,收益是什么,纯技术类还是包含产品类

    3.团队方案:社区是否完善【市场层面,学习圈层面是否足够大】,技术栈是否贴合【与我们团队的技术栈是否贴合】

  • 相关阅读:
    ssm+vue的药品管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。
    Arduino开发实例-旋转编码器RGB-LED调光
    深入解析智慧互联网医院系统源码:医院小程序开发的架构到实现
    Zephyr调度算法
    Spring是什么?为什么要使用Spring?
    中国台湾板块上新啦!
    关于bug的分类和定金,终于有人讲明白了
    利用spring写一个反向代理
    Java 基于 SpringBoot 的校园疫情防控系统
    函数指针数组指针(指向函数指针数组的指针)
  • 原文地址:https://blog.csdn.net/qq_35729091/article/details/132605316