react【五】redux/reduxToolkit/手写connext

文章目录

  • 1、回顾纯函数
  • 2、redux
    • 2.1 redux的基本使用
    • 2.2 通过action修改store的数值
    • 2.3 订阅state的变化
    • 2.4 目录结构
    • 2.5 Redux的使用过程
    • 2.6 redux的三大原则
    • 2.7 Redux官方图
  • 3、redux在React中的使用
  • 4、react-redux使用
    • 4.1 react-redux的基本使用
    • 4.2 异步请求 redux-thunk
    • 4.3 对redux代码结构进行优化 和 redux-devtools
  • 5、ReduxToolkit
    • 5.1 基本使用
    • 5.2 异步操作 写法1
    • 5.3 异步操作 写法2
  • 6、手写connext
  • 7、合并中间件
  • 8、React中的state如何管理

1、回顾纯函数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、redux

2.1 redux的基本使用

  • pm install redux --save
  • 在这里插入图片描述
  • store
const { createStore } = require("redux");

// 1.state数据
const initialState = {
  name: "kiki",
  age: "18",
};

// 2.reducer纯函数
function reducer() {
  return initialState;
}

// 3.创建store
const store = createStore(reducer);

module.exports = store;

在这里插入图片描述

2.2 通过action修改store的数值

在这里插入图片描述

const { createStore } = require("redux");
const { ADD_NUMBER, CHANGE_NAME } = require("./constants");

// 1.state数据
const initialState = {
  name: "kiki",
  num: 18,
};

// 2.reducer纯函数

// 两个参数
// 参数1:store目前保存的state 设置默认参数
// 参数2:本次需要更新的action
// 返回值 他的返回值作为之后存储在store的数值 因为第一次调用没有数值 所以设置默认值
function reducer(state = initialState, action) {
  console.log(state, action); // { name: 'kiki', num: '18' } { type: '@@redux/INIT0.n.r.y.w.j' }

  switch (action.type) {
    case ADD_NUMBER:
      // 这里需要创建新的对象的返回 否则页面发现state没有发生变化不会更新界面
      return { ...state, num: state.num + action.num };

    case CHANGE_NAME:
      return { ...state, name: action.name };
    default:
      return state;
  }
}

// 3.创建store
const store = createStore(reducer);

module.exports = store;

在这里插入图片描述

2.3 订阅state的变化

在这里插入图片描述

2.4 目录结构

在这里插入图片描述
在这里插入图片描述

2.5 Redux的使用过程

在这里插入图片描述

2.6 redux的三大原则

在这里插入图片描述

2.7 Redux官方图

在这里插入图片描述

3、redux在React中的使用

在这里插入图片描述

4、react-redux使用

yarn add react-redux

4.1 react-redux的基本使用

在这里插入图片描述

在这里插入图片描述

import React, { PureComponent } from "react";
import { connect } from "react-redux";
// import store from "../store"
import { addNumberAction, subNumberAction } from "../store/actionCreators";

export class About extends PureComponent {
  calcNumber(num, isAdd) {
    if (isAdd) {
      console.log("加", num);
      this.props.addNumber(num);
    } else {
      console.log("减", num);
      this.props.subNumber(num);
    }
  }

  render() {
    const { counter, banners, recommends } = this.props;

    return (
      <div>
        <h2>About Page: {counter}</h2>
        <div>
          <button onClick={(e) => this.calcNumber(6, true)}>+6</button>
          <button onClick={(e) => this.calcNumber(88, true)}>+88</button>
          <button onClick={(e) => this.calcNumber(6, false)}>-6</button>
          <button onClick={(e) => this.calcNumber(88, false)}>-88</button>
        </div>
      </div>
    );
  }
}

// connect()返回值是一个高阶组件
// function mapStateToProps(state) {
//   return {
//     counter: state.counter
//   }
// }

// function fn2(dispatch) {
//   return {
//     addNumber(num) {
//       dispatch(addNumberAction(num))
//     },
//     subNumber(num) {
//       dispatch(subNumberAction(num))
//     }
//   }
// }

const mapStateToProps = (state) => ({
  counter: state.counter,
  banners: state.banners,
  recommends: state.recommends,
});

const mapDispatchToProps = (dispatch) => ({
  addNumber(num) {
    dispatch(addNumberAction(num));
  },
  subNumber(num) {
    dispatch(subNumberAction(num));
  },
});

// connect是高阶组件
export default connect(mapStateToProps, mapDispatchToProps)(About);

4.2 异步请求 redux-thunk

yarn add redux-thunk
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.3 对redux代码结构进行优化 和 redux-devtools

每个页面可能都会有自己的store为了方便维护,将store按照页面划分
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

import { createStore, applyMiddleware, compose, combineReducers } from "redux";
import thunk from "redux-thunk";

import counterReducer from "./counter";
import homeReducer from "./home";
import userReducer from "./user";

// 正常情况下 store.dispatch(object)
// 想要派发函数 store.dispatch(function)

// 将两个reducer合并在一起
const reducer = combineReducers({
  counter: counterReducer,
  home: homeReducer,
  user: userReducer,
});

// combineReducers实现原理(了解)
// function reducer(state = {}, action) {
//   // 返回一个对象, store的state
//   return {
//     counter: counterReducer(state.counter, action),
//     home: homeReducer(state.home, action),
//     user: userReducer(state.user, action)
//   }
// }

// redux-devtools
// trace的功能是可以追踪源码
const composeEnhancers =
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ trace: true }) || compose;

// thunk 是用来发送异步请求的增强写法
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)));

export default store;

在这里插入图片描述

在这里插入图片描述

5、ReduxToolkit

5.1 基本使用

npm install @reduxjs/toolkit react-redux
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 需要在根组件传递store的值
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { changeNumber } from "../store/features/counter";

export class About extends PureComponent {
  changeNum(num) {
    this.props.changeNumber(num);
  }
  render() {
    const { counter } = this.props;
    return (
      <div>
        {counter}
        <button onClick={(e) => this.changeNum(5)}>+5</button>
      </div>
    );
  }
}

const mapStateToProps = (state) => ({
  counter: state.counter.counter,
});

const mapDispatchToProps = (dispatch) => ({
  changeNumber(num) {
    dispatch(changeNumber(num));
  },
});

export default connect(mapStateToProps, mapDispatchToProps)(About);

5.2 异步操作 写法1

在这里插入图片描述

import { createAsyncThunk } from "@reduxjs/toolkit";
import { createSlice } from "@reduxjs/toolkit";
import axios from "axios";

// toolkit已经集成了thunk所以可以直接使用
// 第一个参数是name可以根据自己的喜好取
// 可以把这个函数看成是promise 它跟promise十分相似
export const fetchHomeMultidataAction = createAsyncThunk(
  "fetch/homemultidata",

  // dispatch传递的参数是第一个 extraInfo
  async (extraInfo, { dispatch, getState }) => {
    console.log(extraInfo);
    const res = await axios.get("http://123.207.32.32:8000/home/multidata");

    // 不能直接返回res 没办法直接对其进行序列化
    return res.data;
  }
);

const homeSlice = createSlice({
  name: "home",
  initialState: {
    banner: [],
  },
  reducers: {
    changeBanner(state, { payload }) {
      state.banner = payload;
    },
  },

  // 这里是对异步操作进行操作的方法
  extraReducers: {
    [fetchHomeMultidataAction.pending](state, action) {
      console.log(action);
    },
    [fetchHomeMultidataAction.fulfilled](state, { payload, meta }) {
      // 异步操作返回的参数
      state.banner = payload.data.banner.list;
      // 在dispatch时传递的参数
      console.log(meta.arg);
    },
    [fetchHomeMultidataAction.rejected](state, action) {
      console.log("fetchHomeMultidataAction rejected");
    },
  },
});

export const { changeBanner } = homeSlice.actions;
export default homeSlice.reducer;

在这里插入图片描述

5.3 异步操作 写法2

在这里插入图片描述

import { createAsyncThunk } from "@reduxjs/toolkit";
import { createSlice } from "@reduxjs/toolkit";
import axios from "axios";

// toolkit已经集成了thunk所以可以直接使用
// 第一个参数是name可以根据自己的喜好取
// 可以把这个函数看成是promise 它跟promise十分相似
export const fetchHomeMultidataAction = createAsyncThunk(
  "fetch/homemultidata",

  // dispatch传递的参数是第一个 extraInfo
  async (extraInfo, { dispatch, getState }) => {
    console.log(extraInfo);
    const res = await axios.get("http://123.207.32.32:8000/home/multidata");

    // 不能直接返回res 没办法直接对其进行序列化
    return res.data;
  }
);

const homeSlice = createSlice({
  name: "home",
  initialState: {
    banner: [],
  },
  reducers: {
    changeBanner(state, { payload }) {
      state.banner = payload;
    },
  },

  // 这里是对异步操作进行操作的方法
  // extraReducers: {
  //   [fetchHomeMultidataAction.pending](state, action) {
  //     console.log(action);
  //   },
  //   [fetchHomeMultidataAction.fulfilled](state, { payload, meta }) {
  //     // 异步操作返回的参数
  //     state.banner = payload.data.banner.list;
  //     // 在dispatch时传递的参数
  //     console.log(meta.arg);
  //   },
  //   [fetchHomeMultidataAction.rejected](state, action) {
  //     console.log("fetchHomeMultidataAction rejected");
  //   },
  // },
  extraReducers: (builder) => {
    builder
      .addCase(fetchHomeMultidataAction.pending, (state, action) => {
        console.log("fetchHomeMultidataAction pending");
      })
      .addCase(fetchHomeMultidataAction.fulfilled, (state, { payload }) => {
        state.banners = payload.data.banner.list;
        state.recommends = payload.data.recommend.list;
      });
  },
});

export const { changeBanner } = homeSlice.actions;
export default homeSlice.reducer;

6、手写connext

// connect的参数:
// 参数一: 函数
// 参数二: 函数
// 返回值: 函数 => 高阶组件

import { PureComponent } from "react";
import { StoreContext } from "./StoreContext";
// import store from "../store"

//  实际上就是一个高阶函数里面嵌套一个高阶组件
export function connect(mapStateToProps, mapDispatchToProps, store) {
  // 高阶组件: 函数
  return function (WrapperComponent) {
    class NewComponent extends PureComponent {
      //  接收的第二个参数就是context
      constructor(props, context) {
        super(props);

        this.state = mapStateToProps(context.getState());
      }

      componentDidMount() {
        // 因为页面发生改变是connect自己内部实现的 我们自己手写的话 要手动调用
        this.unsubscribe = this.context.subscribe(() => {
          // 不能直接通过强制刷新 不然性能很低
          // this.forceUpdate()

          // 执行ToProps的方法 自己判断是否state发生了变化
          this.setState(mapStateToProps(this.context.getState()));
        });
      }

      componentWillUnmount() {
        this.unsubscribe();
      }

      render() {
        // 传递进来的两个方法进行调用 再把他们的数值传递给组件 实现了高阶组件的增强
        const stateObj = mapStateToProps(this.context.getState());
        const dispatchObj = mapDispatchToProps(this.context.dispatch);
        return (
          <WrapperComponent {...this.props} {...stateObj} {...dispatchObj} />
        );
      }
    }

    // 为了避免每次store都是需要传入进来 所以创建了一个context 在注册应用的时候就将他导入
    NewComponent.contextType = StoreContext;

    return NewComponent;
  };
}

在这里插入图片描述
在这里插入图片描述

7、合并中间件

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8、React中的state如何管理

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java并发基础:PriorityBlockingQueue全面解析!

内容概要 PriorityBlockingQueue类能高效处理优先级任务&#xff0c;确保高优先级任务优先执行&#xff0c;它内部基于优先级堆实现&#xff0c;保证了元素的有序性&#xff0c;同时&#xff0c;作为BlockingQueue接口的实现&#xff0c;它提供了线程安全的队列操作&#xff0…

系统架构26 - 软件架构设计(5)

特定领域软件体系结构 定义不同定义必备特征领域 基本活动领域分析领域设计领域实现 参与人员建立过程 特定领域软件体系结构的主要目的是在一组相关的应用中共享软件体系结构。 定义 DSSA (Domain Specific Software Architecture) 就是在一个特定应用领域中为一组应用提供组…

算法-16-并查集

并查集简介 并查集&#xff1a;一开始&#xff0c;把a&#xff0c;b&#xff0c;c放入并查集&#xff0c;a自己一个集合&#xff0c;b自己一个&#xff0c;c自己一个 提供的方法 1.boolean isSameSet(a,b)&#xff0c;判断ab是否在同一个集合 2.void union(a,b),把a所…

基于PHP的学生管理系统

前言 基于PHP的学生管理系统&#xff1b; 实现 登录、注册、学生信息、修改学生、删除学生、查询学生、添加学生等功能 &#xff1b; 环境准备 开发平台&#xff1a;PhpStrom2022.1.2 、Phpstudy_pro 数据库&#xff1a;MySQL5.7.26 技术架构 Bootstrap PHP7.3.4html5css3 项目…

vue安装使用less,解决与webpack的冲突

第077个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使用&#xff0c;computed&a…

C++-带你深度理解string类的常见接口

1. 为什么学习string类&#xff1f; C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不太符合OOP的思想&#xff0c;而且底层空间需…

LeetCode周赛——384

1.修改矩阵&#xff08;模拟&#xff09; class Solution { public:vector<vector<int>> modifiedMatrix(vector<vector<int>>& matrix) {int n matrix.size();int m matrix[0].size();vector<int> ans(m);for(int i 0; i < m; i)for(…

如何写好一个简历

如何编写求职简历 论Java程序员求职中简历的重要性 好简历的作用 在求职过程中&#xff0c;一份好的简历是非常重要的&#xff0c;它甚至可以直接决定能否被面试官认可。一份出色或者说是成功的个人简历&#xff0c;最根本的作用是能让看这份简历的人产生一定要见你的强烈愿…

腾讯云4核8G服务器够用吗?来看看支持多少人访问!

腾讯云4核8G服务器支持多少人在线访问&#xff1f;支持25人同时访问。实际上程序效率不同支持人数在线人数不同&#xff0c;公网带宽也是影响4核8G服务器并发数的一大因素&#xff0c;假设公网带宽太小&#xff0c;流量直接卡在入口&#xff0c;4核8G配置的CPU内存也会造成计算…

基于 Python 的大数据的电信反诈骗系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

【c语言】字符串常见函数 下

&#x1f388;个人主页&#xff1a;甜美的江 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;c语言 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步&a…

文生图提示词:视角选择

构图和视角 --视角选择 Perspective Choices 涵盖从基本的摄影视角到更复杂和专业的视角技巧&#xff0c;展示了在视觉艺术创作中可以采用的多样化视角选择。 Eye Level 眼平线视角 High Angle 高角度 Low Angle 低角度 Birds Eye View 鸟瞰视角 Worms Eye View 虫视视角 Front…

【51单片机】直流电机驱动(PWM)(江科大)

1.直流电机介绍 直流电机是一种将电能转换为机械能的装置。一般的直流电机有两个电极,当电极正接时,电机正转,当电极反接时,电机反转 直流电机主要由永磁体(定子)、线圈(转子)和换向器组成 除直流电机外,常见的电机还有步进电机、舵机、无刷电机、空心杯电机等 2.电机驱动…

使用UMAP降维可视化RAG嵌入

大型语言模型&#xff08;LLMs&#xff09;如 GPT-4 已经展示了出色的文本理解和生成能力。但它们在处理领域特定信息方面面临挑战&#xff0c;比如当查询超出训练数据范围时&#xff0c;它们会产生错误的答案。LLMs 的推理过程也缺乏透明度&#xff0c;使用户难以理解达成结论…

Qt之条件变量QWaitCondition详解

QWaitCondition内部实现结构图&#xff1a; 相关系列文章 C之Pimpl惯用法 目录 1.简介 2.示例 2.1.全局配置 2.2.生产者Producer 2.3.消费者Consumer 2.4.测试例子 3.原理分析 3.1.辅助函数CreateEvent 3.2.辅助函数WaitForSingleObject 3.3.QWaitConditionEvent …

C++笔记1:操纵符输入输出

C操纵符用来控制输出控制&#xff0c;一是输出的形式&#xff0c;二是控制补白的数量和位置。本文记录一下&#xff0c;在一些笔试的ACM模式可能有用。其中1-4节的部分是关于格式化输入输出操作&#xff0c;5-6节的部分是关于未格式化输入输出操作。 1. 控制布尔值的格式 一般…

uniapp API文档地址 以及 HBuilder安装

uniapp API文档地址 以及 HBuilder安装 一、进入 当前网站 uni-app 官网 [uni-app](https://zh.uniapp.dcloud.io/quickstart-hx.html)二、点击截图下载文件 三、 进入 当前网站 &#xff08;https://www.dcloud.io/hbuilderx.html&#xff09; 浏览器会识别 也可以自行选择…

基于GIS、RS、VORS模型、CCDM模型、geodetecto、GWR模型集成的生态系统健康的耦合协调分析

详情点击公众号&#xff1a;技术科研吧 链接&#xff1a;基于GIS、RS、VORS模型、CCDM模型、geodetecto、GWR模型集成的生态系统健康的耦合协调分析 前沿 当空间大数据、云计算与人工智能发生碰撞,地理服务产业也不断发生变革与进步。ArcGIS Pro 是一个专业的桌面 GIS 应用程…

17 外排序

排序分为内排序和外排序&#xff0c;内排序是在内存中的排序。外排序指在磁盘中文件的排序&#xff0c;因为在磁盘中&#xff0c;不能进行下标访问&#xff0c;归并排序经常用于磁盘中文件的排序 假如有10亿个整形数据在磁盘中&#xff0c;要对它排序&#xff0c;内存中只有1G…

水果FL Studio21.2最新中文版功能特点介绍

FL Studio 21的特点和优势包括&#xff1a; 丰富的主题换肤&#xff1a;用户可以通过调整色调、饱和度、亮度、文本、仪表和步进序列器的颜色&#xff0c;来个性化定制FL Studio 21的外观&#xff0c;使其更符合个人审美或工作风格。更快的音频编辑&#xff1a;FL Studio 21集…