React学习(四) --- Redux

文章目录

  • [1. Redux前置知识](#1. Redux前置知识)
    • [1.1 纯函数回顾](#1.1 纯函数回顾)
    • [1.2 Redux的三个核心概念](#1.2 Redux的三个核心概念)
  • [2. Redux使用](#2. Redux使用)
    • [2.1 规范化Redux结构](#2.1 规范化Redux结构)
    • [2.2 Redux的三大规则](#2.2 Redux的三大规则)
    • [2.3 react-redux --- 高阶组件封装库](#2.3 react-redux --- 高阶组件封装库)
    • [2.4 异步获取数据](#2.4 异步获取数据)
    • [2.5 react代码调试工具](#2.5 react代码调试工具)
    • [2.6 Redux模块拆分](#2.6 Redux模块拆分)
  • [3. RTK工具包](#3. RTK工具包)
    • [3.1 redux toolkit](#3.1 redux toolkit)
    • [3.2 使用RTK](#3.2 使用RTK)
      • [3.2.1 创建reducer片段 ---createSlice](#3.2.1 创建reducer片段 ---createSlice)

1. Redux前置知识

1.1 纯函数回顾

  • 确定输入,一定会产生确定的输出;
  • 函数在执行过程中,不能产生副作用;


判断下面三个函数是否是纯函数

答案:

  1. 不是 (依赖外界)
  2. 不是 (改变外界)

1.2 Redux的三个核心概念

  1. store

  2. action

  3. reducer❗️

reducer是一个纯函数,主要人物是将stateaction结合起来生成一个新的state返回,这个返回值将替换之前的state

修改state流程:

  • state.dispatch({type: ... , action: {...})
  • 触发reducer ,产生新state
  • state更新

如何知道store数据修改了呢?

答:使用subscribe

javascript 复制代码
componentDidMount() {
    // 订阅store数据
    this.unsubscribe = store.subscribe(() => {
      console.log('store change:', store.getState());
    })
  }

  componentWillUnmount() {
    // 取消订阅
    this.unsubscribe()
  }

2. Redux使用

2.1 规范化Redux结构

index.js

  • 创建store
  • 传入reducer
javascript 复制代码
import { createStore } from 'redux';

// const { createStore } = require('redux');  // createRedux现已弃用

const initialStore = {
  name: "Anonymous",
}

const store = createStore(reducer)

export default store;

actionsCreators.js

  • 创建actions
javascript 复制代码
// actions创建
export const changeNameAction = (name) => ({ type: 'change_name', name })

reducer.js

  • 单独保存reducer
javascript 复制代码
import { ADD_NUMBER, CHANGE_NAME } from "./constants";

// reducer 是一个纯函数
// 接收两个参数 state: 之前的状态   action: 描述要产生的改变
export function reducer(state = initialStore, action) {
  switch (action.type) {
    case CHANGE_NAME:
      return { ...state, name: action.name };
    case ADD_NUMBER:
      return { name }
    default:
      return state;
  }
}

contants.js

  • 保存type常量
javascript 复制代码
// 常量
export const ADD_NUMBER = 'add_number'
export const CHANGE_NAME = 'change_name'

2.2 Redux的三大规则

  • 单一数据源
    • 整个应用程序的state被存储在一颗object tree中,并且这个object tree只存储在一个store中:
    • Redux并没有强制让我们不能创建多个Store,但是那样做并不利于数据的维护;
    • 单一的数据源可以让整个应用程序的state变得方便维护、追踪、修改;
  • State是只读的
    • 唯一修改State的方法一定是触发action,不要试图在其他地方通过任何的方式来修改State;
    • 这样就确保了View或网络请求都不能直接修改state,它们只能通过action来描述自己想要如何修改state;
    • 这样可以保证所有的修改都被集中化处理 ,并且按照严格的顺序来执行,所以不需要担心race condition(竟态)的问题;
  • 使用纯函数来执行修改
    • 通过reducer将旧state和actionsl联系在一起,并且返回一个新的State:
    • 随着应用程序的复杂度增加,我们可以将reducer拆分成多个小的reducers,分别操作不同state tree的一部分;
    • 但是所有的reducer都应该是纯函数,不能产生任何的副作用;


2.3 react-redux --- 高阶组件封装库

之前讲到了高阶组件,在实际开发中我们一般使用封装好的库直接调用,而不是自己封装高阶组件,现在来学习一下react-redux这个高阶组件库,这个库主要是将reactredux联系在一起。

2.4 异步获取数据

从服务器获取数据我们可以选择在组件的componnetDidMount中发送请求获取,但其实获取数据也是需要在redux中去完成的。

所以我们选择在传递action时先获取数据再传递到reducer,但如果我们是这样写的:

javascript 复制代码
 axios.get("http://123.207.32.32:8000/home/multidata").then(res => {
    console.log(res.data);
    return { type: CHANGE_BANNERS, banners: [] }
  }).catch(err => {
    return { type: CHANGE_BANNERS, banners: [] }
  })

也就是获取数据后直接返回一个action对象,但其实返回的会是一个Promise对象,不符合redux的规范(传入一个action对象或者一个中间件函数)。

中间件我们需要使用到redux-thunk这个库,首先进行安装:

npm i redux-thunk

javascript 复制代码
const store = createStore(reducer, applyMiddleware(thunk));

之后就可以创建异步获取数据的action

javascript 复制代码
// 异步获取数据的action
export const fetchHomeDataAction = () => {
  // 使用redux-thunk中间件,返回一个函数(内置dispatch和getState)
  return (dispatch, getState) => {
    axios.get("http://123.207.32.32:8000/home/multidata").then(res => {
      console.log(res.data, res.data.data.banner.list);
      dispatch(changeBannersAction(res.data.data.banner.list))
    })
  }
}

需要注意的是返回的函数中thunk内置了dispatchgetState,这里只需要调用普通的action修改数据即可。

2.5 react代码调试工具

首先安装这两个工具

  • redux-devtools
  • react-devtools

默认开发环境开启,生产环境关闭。

2.6 Redux模块拆分

3. RTK工具包

3.1 redux toolkit

  • 在前面我们学习Redux的时候应该已经发现,redux的编写逻辑过于的繁琐和麻烦。
  • 并且代码通常分拆在多个文件中(虽然也可以放到一个文件管理,但是代码量过多,不利于管理);
  • ReduxToolkit包旨在成为编写Redux逻辑的标准方式,从而解决上面提到的问题;
  • 在很多地方为了称呼方便,也将之称为"RTK";

npm i @reduxjs/tookit react-redux

3.2 使用RTK

3.2.1 创建reducer片段 ---createSlice

  • name: 代替action的type;
  • initialState: 初始值;
  • reducers: 与之前的一样,但这里需要注意是函数
javascript 复制代码
import { createSlice } from "@reduxjs/toolkit";

const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    counter: 888
  },
  reducers: {
    addNumber(state, action) {
      state.counter++
    }
  }
})

// 导出的是counterSlice.reducer  (不是counterSlice.reducers)
export default counterSlice.reducer

index.js

javascript 复制代码
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from './modules/counter';

const store = configureStore({
  reducer: {
    counter: counterReducer
  }
})

export default store;
相关推荐
Never_Satisfied4 小时前
在JavaScript / HTML中,div容器在内容过多时不显示超出的部分
开发语言·javascript·html
im_AMBER4 小时前
CSS 01【基础语法学习】
前端·css·笔记·学习
向阳花开_miemie4 小时前
Android音频学习(二十二)——音频接口
学习·音视频
胡萝卜3.04 小时前
深入理解string底层:手写高效字符串类
开发语言·c++·学习·学习笔记·string类·string模拟实现
fanstering4 小时前
腾讯混元P3-SAM: Native 3D Part Segmentation
笔记·学习·3d·点云
ZHOUYUANN4 小时前
我用JavaScript复刻了某宝的小游戏动物大迁徙消消乐
前端·javascript·游戏开发
Asort4 小时前
JavaScript设计模式(十三)——责任链模式:构建灵活高效的请求处理链
前端·javascript·设计模式
摸着石头过河的石头5 小时前
JavaScript继承与原型链:揭开对象传承的神秘面纱
前端·javascript
LRH5 小时前
React 双缓存架构与 diff 算法优化
前端·react.js