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

目录

扩展学习资料

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

@/src/reducer/index.js

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

@src/reducer/reselect/index.js

@/src/actions/reselect/index.js

@/src/containers\reselect\index.jsx

@/src/store/index.js

[Immutable Data](#Immutable Data)

Immutable方案

@/src/containers/immutable/index.jsx

@/src/actions/immutable/index.js

@/src/reducer/immutable/index.js

[redux-actions & @rematch/core & dva【比较高阶状态管理方案】](#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 & @rematch/core & dva)


扩展学习资料

|---------------|----------------------------------------------------------------------------------------------------------|----|
| 名称 | 链接 | 备注 |
| redux-actions | Introduction - redux-actions | 英文 |
| @rematch/core | Rematch | Rematch | |
| dva | 介绍 | DvaJS | |

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

@/src/reducer/index.js

javascript 复制代码
import { combineReducers } from 'redux';
import homeReducer from './home';
import reSelectReducer from './reselect';
import immutableReducer from './immutable';
import reduxActionsReducer from './redux-actions';
// console.log(reSelectReducer());
// 合并多个reducer
// 扩展性
export default combineReducers({
  homeReducer,
  reSelectReducer,
  immutableReducer,
  reduxActionsReducer,
});

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

  • 针对mapStateToProps中state在同一数据源中需要筛选的场景
  • mapStateToProps中state如果带有筛选函数,会导致每次返回新对象

@src/reducer/reselect/index.js

javascript 复制代码
import * as types from '@/actions/mutation-types';
const initialState = {
  reSelectList: [{
    key: '001',
    status: true,
    name: 'flex-reselect-1',
  }, {
    key: '002',
    status: true,
    name: 'flex-reselect-2',
  }, {
    key: '003',
    status: false,
    name: 'flex-reselect-3',
  }, {
    key: '004',
    status: true,
    name: 'flex-reselect-4',
  }, {
    key: '005',
    status: false,
    name: 'flex-reselect-5',
  }, {
    key: '006',
    status: false,
    name: 'flex-reselect-6',
  }, {
    key: '007',
    status: true,
    name: 'flex-reselect-7',
  }],
  filterStatus: 'FILTER_ALL_DATA',
};
const mutations = {
  [types.FILTER_ALL_DATA](state) {
    return { ...state };
  },
  [types.UPDATE_FILTER_STATUS](state, action) {
    return {
      ...state,
      filterStatus: action.payload,
    };
  },
};
export default function (state = initialState, action) {
  if (!mutations[action.type]) return state;
  return mutations[action.type](state, action);
}

@/src/actions/reselect/index.js

javascript 复制代码
import * as types from '../mutation-types';
export function filterData(data, filter) {
  console.log(filter, 'filter', Date.now());
  switch (filter) {
  case types.FILTER_ALL_DATA:
    return data;
  case types.FILTER_SUCCESS_STATUS:
    return data.filter(item => item.status);
  case types.FILTER_FAIL_STATUS:
    return data.filter(item => !item.status);
  default:
    return data;
  }
}
export function updateFilterStatus(params) {
  return {
    type: types.UPDATE_FILTER_STATUS,
    payload: params,
  };
}

@/src/containers\reselect\index.jsx

javascript 复制代码
import React, { Component } from 'react';
import propTypes from 'prop-types';
import { connect } from 'react-redux';
// 可缓存的筛选项,当数据量大的时候,可以节省diff时间,提升渲染效率
import { createSelector } from 'reselect';
import {
  filterData,
  updateFilterStatus,
} from '@/actions/reselect';
const filterStatusMap = {
  1: 'FILTER_ALL_DATA',
  2: 'FILTER_SUCCESS_STATUS',
  3: 'FILTER_FAIL_STATUS',
};
const getReselectList = (state) => state.reSelectReducer.reSelectList;
const getFilterStatus = (state) => state.reSelectReducer.filterStatus;
// 一个可以缓存的数据源,避免了数据的重复计算,和页面更新
const filterReselectData = createSelector(
  [getReselectList, getFilterStatus],
  (list, filter) => filterData(list, filter),
);
// filterData(
//   state.reSelectReducer.reSelectList,
//   state.reSelectReducer.filterStatus,
// )
@connect(
  (state) => ({
    filterList: filterReselectData(state),
  }),
  (dispatch) => ({
    updateFilterStatus: (params) => dispatch(updateFilterStatus(params)),
  }),
)
export default class ReselectDemo extends Component {
  handleUpdate = (signal) => {
    const { updateFilterStatus } = this.props;
    updateFilterStatus(filterStatusMap[signal]);
    // console.log(signal, this.props, updateFilterStatus);
  }
  render() {
    const { filterList } = this.props;
    return (
      <div>
        <>
          {filterList.map(item => (
            <div key={item.key}>
              <span>{item.name}</span>
              &nbsp;&nbsp;
              <span>{String(item.status)}</span>
            </div>
          ))}
        </>
        <button type="button" onClick={() => this.handleUpdate(1)}>全部</button>
        <button type="button" onClick={() => this.handleUpdate(2)}>成功</button>
        <button type="button" onClick={() => this.handleUpdate(3)}>失败</button>
      </div>
    );
  }
}
ReselectDemo.propTypes = {
  filterList: propTypes.arrayOf(propTypes.object),
  updateFilterStatus: propTypes.func,
};
ReselectDemo.defaultProps = {
  filterList: [],
  updateFilterStatus: () => null,
};

@/src/store/index.js

javascript 复制代码
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import reducers from '@/reducer';
const middlewares = [thunk];
// 配合浏览器安装的redux开发者工具
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
export default createStore(
  reducers,
  composeEnhancers(applyMiddleware(...middlewares)),
);

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

javascript 复制代码
import React, { Component } from 'react';
import { connect } from 'react-redux';
import propTypes from 'prop-types';
import updateImmutableData from '@/actions/immutable';
@connect(
  (state) => {
    console.log(state.immutableReducer);
    return ({
      complexData: state.immutableReducer.complexData,
    });
  },
  (dispatch) => ({
    updateImmutableData: (params) => dispatch(updateImmutableData(params)),
  }),
)
export default class ImmutableDemo extends Component {
  handleClick = () => {
    const { updateImmutableData } = this.props;
    updateImmutableData('immutable 云');
  }
  render() {
    const { complexData } = this.props;
    return (
      <div>
        <div>
          {complexData?.commonInfo?.name?.firstName}
        </div>
        <button type="button" onClick={this.handleClick}>更改</button>
      </div>
    );
  }
}
ImmutableDemo.propTypes = {
  complexData: propTypes.objectOf(propTypes.object),
  updateImmutableData: propTypes.func,
};
ImmutableDemo.defaultProps = {
  complexData: {},
  updateImmutableData: () => null,
};

@/src/actions/immutable/index.js

javascript 复制代码
import * as types from '../mutation-types';
export default function updateImmutableData(params) {
  return {
    type: types.UPDATE_IMMUTABLE_DATA,
    payload: params,
  };
}

@/src/reducer/immutable/index.js

javascript 复制代码
import produce from 'immer';
import * as types from '@/actions/mutation-types';
const initialState = {
  complexData: {
    commonInfo: {
      name: {
        firstName: '云',
        secondName: 'Fedora',
      },
    },
    specialInfo: {
      address: '网商路24599号',
    },
  },
};
const mutations = {
  [types.UPDATE_IMMUTABLE_DATA](state, action) {
    return produce(state, draftState => {
      // eslint-disable-next-line no-param-reassign
      draftState.complexData.commonInfo.name.firstName = action.payload;
      console.log('oldState', state);
    });
    // const { complexData } = state;
    // const newComplexData = { ...complexData };
    // newComplexData.commonInfo.name.firstName = action.payload;
    // 改变了源,产生了副作用,无法回溯
    // console.log('newComplexData Vs complexData', newComplexData, complexData);
    // return {
    //   ...state,
    //   complexData: newComplexData,
    // };
  },
};
export default function (state = initialState, action) {
  if (!mutations[action.type]) return state;
  return mutations[action.type](state, action);
}

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

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

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

javascript 复制代码
import * as types from '../mutation-types';
export default function updateReduxActions(params) {
  return {
    type: types.UPDATE_REDUX_ACTIONS_DATA,
    payload: params,
  };
}

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

javascript 复制代码
import React, { Component } from 'react';
import { connect } from 'react-redux';
import propTypes from 'prop-types';
@connect((state) => state.reduxActionsReducer)
export default class ReduxActionsDemo extends Component {
  render() {
    const { actionName } = this.props;
    return (
      <div>
        {actionName}
      </div>
    );
  }
}
ReduxActionsDemo.propTypes = {
  actionName: propTypes.string,
};
ReduxActionsDemo.defaultProps = {
  actionName: '',
};

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

javascript 复制代码
import * as types from '@/actions/mutation-types';
const initialState = {
  actionName: '云',
};
const mutations = {
  [types.UPDATE_REDUX_ACTIONS_DATA](state, action) {
    return {
      ...state,
      actionName: action.payload,
    };
  },
};
export default function (state = initialState, action) {
  if (!mutations[action.type]) return state;
  return mutations[action.type](state, action);
}

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.团队方案:社区是否完善【市场层面,学习圈层面是否足够大】,技术栈是否贴合【与我们团队的技术栈是否贴合】

相关推荐
四喜花露水25 分钟前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
前端Hardy34 分钟前
HTML&CSS: 实现可爱的冰墩墩
前端·javascript·css·html·css3
web Rookie1 小时前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript
Au_ust1 小时前
css:基础
前端·css
帅帅哥的兜兜1 小时前
css基础:底部固定,导航栏浮动在顶部
前端·css·css3
工业甲酰苯胺1 小时前
C# 单例模式的多种实现
javascript·单例模式·c#
yi碗汤园1 小时前
【一文了解】C#基础-集合
开发语言·前端·unity·c#
就是个名称1 小时前
购物车-多元素组合动画css
前端·css
编程一生2 小时前
回调数据丢了?
运维·服务器·前端
丶21362 小时前
【鉴权】深入了解 Cookie:Web 开发中的客户端存储小数据
前端·安全·web