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

news2024/9/24 15:23:43

目录

扩展学习资料

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

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

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

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

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

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

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

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

@/src/reducer/immutable/index.js

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

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/985977.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[B题]2023 年全国大学生数学建模比赛思路、代码更新中.....

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

力扣刷题总结一:模拟+哈希表+双指针+前缀和+滑动窗口

模拟 根据题目意思&#xff0c;捋清整个流程&#xff0c;使用代码去模拟整个流程 例题 种花问题 class Solution:def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool:# 模拟&#xff0c;在数组前后各添加1个0&#xff0c;从第1个元素到倒数第2个元素&…

CMake输出编译时间信息

使用CMake进行编译的代码&#xff0c;有时候会希望获得当前代码编译的时间信息&#xff0c;使用CMake提供的函数和宏等功能可以实现这个功能&#xff0c;下面是实现这个功能的一段代码 原文链接&#xff1a; CMake输出编译时间信息

YOLOV7改进-最新的可变形卷积V3

DCNv3 1、先编译这个文件,放到models文件夹下,再编译 2、编译命令 3、复制到common文件最后 4、源文件用的是LN,由于这里用的都是LN,所以也改了 5、原文也是没接激活函数的,但是按照yolo格式来说,会接一个 6、不加激活函数就把act去掉 7、DCNv3只在gpu上运行,所以下…

记一次时间序列算法的自回归预测--ARAutoreg

背景 最近公司给客户要做一些数据的预测&#xff0c;但是客户不清楚哪些做起来比较符合他们的&#xff0c;于是在经过与业务方的沟通&#xff0c;瞄准了两个方面的数据 1.工程数据&#xff1a;对工程数据做评估&#xff0c;然后做预警&#xff0c;这个想法是好的&#xff0c;…

java 咖啡餐厅管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 咖啡餐厅管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0…

【2023最新版】DataGrip使用MySQL教程

目录 一、安装MySQL 二、安装DataGrip 三、DataGrip使用MySQL 1. 新建项目 2. DataGrip连接MySQL 下载驱动文件 填写root密码 测试 成功 3. DataGrip操作MySQL 四、MySQL常用命令 1. 登录 2. 帮助 3. 查询所有数据库 一、安装MySQL MySQL是一种开源的关系型数据库…

java: 读取snakeyaml-1.26.jar各种jar包时出错; error in opening zip file

可能的问题 jar有问题idea没有权限等等其他问题。但执行后报错就是读取不了&#xff0c;还报error in opening zip file这个错。 解决问题 我的错就是jar包有问题。我先后进行了很多次把jar包位置里的东西全部删除&#xff0c;然后重新maven下载但是不管用。最后从网站上下载…

Kotlin委托Delegate托管by

Kotlin委托Delegate托管by import kotlin.reflect.KPropertyfun main() {var user: String by MyDelegate()user "fly"println(user) }class MyDelegate {private var v: String? nulloperator fun getValue(thisRef: Any?, property: KProperty<*>): Stri…

基于SSM的实验室耗材管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

解决方案 | 电子签让公共事业服务更便捷

为深入贯彻落实国务院关于深化“放管服”改革的号召&#xff0c;各地政府纷纷出台创新举措&#xff0c;优化营商环境&#xff0c;将公共事业服务纳入“一网通办”的范畴。 政策助力&#xff0c; 让公共事业服务实现“足不出户”线上办 上海&#xff1a;上海市大数据中心与国网…

Discourse 的无效附件清理

Discourse 对上传的附件会进行清理&#xff0c;对于一些没有任何被引用的附件&#xff0c;Discourse 会认为是垃圾而清理掉。 原因应该是为了降低存储空间的使用&#xff0c;但是我们目前使用的是 S3 &#xff0c;所以对存储空间并没有太多的要求。 根据官方的说法&#xff0…

SpringBoot配置优先级和Bean管理

SpringBoot配置优先级和Bean管理 1&#xff09;SpringBoot配置优先级2&#xff09;Bean管理【1】获取bean【2】bean作用域【3】第三方bean 1&#xff09;SpringBoot配置优先级 优先级(低>高) application.yaml(忽略)application.ymlapplication.propertiesjava系统属性(-Dxx…

LeetCode(力扣)78. 子集Python

LeetCode78. 子集 题目链接代码 题目链接 https://leetcode.cn/problems/subsets/description/ 代码 class Solution:def subsets(self, nums: List[int]) -> List[List[int]]:result []self.backtracking(nums, result, 0, [])return resultdef backtracking(self, nu…

容器编排学习(一)k8s集群管理

一 Kubernetes 1 概述 就在Docker容器技术被炒得热火朝天之时&#xff0c;大家发现&#xff0c;如果想要将Docker应用于具体的业务实现&#xff0c;是存在困难的一一编排、管理和调度等各个方面&#xff0c;都不容易。于是&#xff0c;人们迫切需要一套管理系统&#xff0…

MIT 6.S081学习笔记(第〇章)

〇、前言 本文涉及 xv6 《第零章 操作系统接口》相关&#xff0c;主要对涉及的进程、I/O、文件描述符、管道、文件等内容产生个人理解&#xff0c;不具有官方权威解释&#xff1b;文章的目录与书中的目录没有严格的相关性&#xff1b;文中会有问题 (Question) 字段&#xff0c…

uniapp里textarea多行文本输入限制数量

uniapp里textarea多行文本域实现输入计数 <template><view class"inputs"><textarea class"text1" maxlength50 placeholder请输入... input"sumfontnum"></textarea><text class"text2">{{fontNum}}/…

软件设计模式(三):责任链模式

前言 前面荔枝梳理了有关单例模式、策略模式的相关知识&#xff0c;这篇文章荔枝将沿用之前的写法根据示例demo来体会这种责任链设计模式&#xff0c;希望对有需要的小伙伴有帮助吧哈哈哈哈哈哈~~~ 文章目录 前言 责任链模式 1 简单场景 2 责任链模式理解 3 Java下servl…

【OJ比赛日历】快周末了,不来一场比赛吗? #09.09-09.15 #15场

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息仅供参考&#xff0c;以比赛官网为准 目录 2023-09-09&#xff08;周六&#xff09; #5场比赛2023-09-10…

Kafka3.0.0版本——消费者(独立消费者消费某一个主题中某个分区数据案例__订阅分区)

目录 一、独立消费者消费某一个主题中某个分区数据案例1.1、案例需求1.2、案例代码1.3、测试 一、独立消费者消费某一个主题中某个分区数据案例 1.1、案例需求 创建一个独立消费者&#xff0c;消费firstTopic主题 0 号分区的数据&#xff0c;所下图所示&#xff1a; 1.2、案…