08_React redux

React redux

  • 一、理解
    • 1、学习文档
    • [2、redux 是什么吗](#2、redux 是什么吗)
    • [3、什么情况下需要使用 redux](#3、什么情况下需要使用 redux)
    • [4、redux 工作流程](#4、redux 工作流程)
    • [5、react-redux 模型图](#5、react-redux 模型图)
  • [二、redux 的三个核心概念](#二、redux 的三个核心概念)
  • [三、redux 的核心 API](#三、redux 的核心 API)
  • [四、使用 redux 编写应用](#四、使用 redux 编写应用)
    • [1、求和案例\_redux 精简版](#1、求和案例_redux 精简版)
      • [1.1 去除 Count 组件自身的状态](#1.1 去除 Count 组件自身的状态)
      • [1.2 src 下建立](#1.2 src 下建立)
      • [1.3 store.js](#1.3 store.js)
      • [1.4 count_reducer.js](#1.4 count_reducer.js)
      • [1.5 在 index.js 中检测 store 中状态的改变,一旦发生改变重新渲染](#1.5 在 index.js 中检测 store 中状态的改变,一旦发生改变重新渲染)
    • [2、求和案例\_redux 完整版](#2、求和案例_redux 完整版)
    • [3、求和案例\_redux 异步 action 版](#3、求和案例_redux 异步 action 版)
    • [4、求和案例\_react-redux 基本使用](#4、求和案例_react-redux 基本使用)
      • [4.1 明确两个概念](#4.1 明确两个概念)
      • [4.2 如何创建一个容器组件------ react-redux 的 connect 函数](#4.2 如何创建一个容器组件—— react-redux 的 connect 函数)
      • [4.3 备注 1:容器组件中的 store 是靠 props 传递的,而不是容器组件中直接引入 store](#4.3 备注 1:容器组件中的 store 是靠 props 传递的,而不是容器组件中直接引入 store)
      • [4.4 备注 2:mapDispatchToProps 也可以是一个对象](#4.4 备注 2:mapDispatchToProps 也可以是一个对象)
    • [5、求和案例\_react-redux 优化](#5、求和案例_react-redux 优化)
    • [6、多组件共享数据\_redux 管理](#6、多组件共享数据_redux 管理)
    • 7、纯函数
    • [8、Redux 开发者工具 redux-devtool](#8、Redux 开发者工具 redux-devtool)
  • 五、项目打包运行

一、理解

1、学习文档

1、英文文档:https://redux.js.org/

2、中文文档:http://www.redux.org.cn/

2、redux 是什么吗

1、redux 是一个专门用于做状态管理 的 JS 库(不是 react 插件库)

2、它可以用在 react、angular、vue 等项目中,但基本与 react 配合使用

3、作用:集中式管理 react 应用中多个组件共享的状态

3、什么情况下需要使用 redux

1、某个组件的状态,需要让其他组件可以随时拿到(共享)

2、一个组件需要改变另一个组件的状态(通信)

3、总体原则:能不用就不用,如果不用比较吃力才考虑使用

4、redux 工作流程

将公共的数据给到 redux,

5、react-redux 模型图

1、所有的 UI 组件都应该包裹一个容器组件,他们是父子关系。

2、容器组件时真正和 redux 打交道的,里面可以随意的使用 redux 的 api

3、UI 组件中不能使用任何 redux 的 api

4、容器组件会传给 UI 组件:

(1)redux 中所保存的状态

(2)用于操作状态的方法

5、备注:容器给 UI 传递:状态(这里的状态是 redux 中的状态)、操作状态的方法,均通过 props 传递

二、redux 的三个核心概念

1、action

1、动作的对象

2、包含 2 个属性:

type: 标识属性,值为字符串,唯一,必要属性

data: 数据属性,值类型任意,可选属性

3、例子:

javascript 复制代码
{type:'ADD_STUDENT',data:{name: 'Tom', age:18}}

action

如果是 Object 的一般对象就是 同步 action

如果值是 function 的对象就是 异步 action

2、reducer

1、用于初始化状态、加工状态

2、加工时,根据旧的 state 和 action,产生新的 state 的纯函数

3、store

1、将 state、action、reducer 联系在一起的对象

2、如何得到此对象?

1)import {createStore} from "redux"

2)import reducer from "./reducer"

3)const store = createStore(reducer)

3、此对象的功能?

1) getState():得到 state

2)dispatch(action):分发 action,触发 reducer 调用,产生新的 state

3)subscribe(listener):注册监听,当产生了新的 state 时,自动调用

三、redux 的核心 API

1、getState()

获取状态

2、dispatch()

分发

四、使用 redux 编写应用

求和应用

展示求和,进行 加、减、结果为奇数加、异步加 运算

1、求和案例_redux 精简版

1.1 去除 Count 组件自身的状态

1.2 src 下建立

-redux

-store.js

-count_reducer.js

1.3 store.js

1.3.1 引入 redux 中的 createStore 函数,创建一个 store

1.3.2 createStore 调用时要传入一个为其服务的 reducer

1.3.3 记得暴露 store 对象

1.4 count_reducer.js

1.4.1 reducer 的本质是一个函数,接收:preState,action ,返回加工后的状态

1.4.2 reducer 有两个作用:初始化状态,加工状态

1.4.3 reducer 被第一次调用时,是 store 自动触发的:

传递的 preState 是 undefined

传递的 action 是 {type: '@@redux/INITn.j.9.n.r.k'}

1.5 在 index.js 中检测 store 中状态的改变,一旦发生改变重新渲染

备注:redux 只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己写

2、求和案例_redux 完整版

新增文件

1、count_action.js 专门用于 创建 action 对象

2、constant.js 放置由于编码疏忽写错 action 中的 type

3、求和案例_redux 异步 action 版

1、明确:延迟的动作不想交给组件自身,想交给 action

2、何时需要异步 action:想要状态进行操作,但是具体的数据靠异步任务返回(非必须)

3、具体编码:

3.1 yarn add redux-thunk, 并配置在 store 中

3.2 创建 action 的函数不再返回一般对象,而是一个函数,该函数中写异步任务

3.3 异步任务有结果后,分发一个同步的 action 去真正操作数据

4、备注:异步 action 不是必须要写的,完全可以自己等待异步任务的结果返回了再去分发同步 action

4、求和案例_react-redux 基本使用

4.1 明确两个概念

1、UI 组件:不能使用任何 redux 的 api,只负责页面的呈现、交互等

2、容器组件:负责和 redux 同学呢,将结果交给 UI 组件

4.2 如何创建一个容器组件------ react-redux 的 connect 函数

connect(mapStateToProps,mapDisapatchToProps)(UI 组件)

mapStateToProps: 映射状态,返回值是一个对象

mapDisapatchToProps:映射操作状态的方法,返回值是一个对象

容器组件的写法:

jsx 复制代码
// 容器组件 react-redux

// 引入Count 的 UI 组件
import CountUI from '../../components/Count'
// 引入 action
import {
  createIncrementAction,
  createDecrementAction,
  createIncrementAsyncAction,
} from '../../redux/count_action'

// 引入 connect 用于连接 UI 组件与 redux
import { connect } from 'react-redux'

/**
 * 1、mapStateToProps 函数返回的是一个对象;
 * 2、返回的对象中的 key 就作为传递给 UI 组件 props 的key, value就作为传递给 UI 组件 props 的value
 * 3、mapStateToProps 用于传递状态
 */
// mapStateToProps 函数的返回值作为状态传递给了 UI 组件
// 返回的对象中的 key 就作为传递给 UI 组件 props 的key, value就作为传递给 UI 组件 props 的value -- 状态
const mapStateToProps = (state) => {
  return {
    count: state,
  }
}

// mapDisapatchToProps 函数返回的对象中的 key 就作为传递给 UI 组件 props 的key, value就作为传递给 UI 组件 props 的value -- 操作状态的方法
const mapDisapatchToProps = (dispatch) => {
  return {
    jia: (data) => {
      // 通知 redux 执行加法
      dispatch(createIncrementAction(data))
    },
    jian: (data) => {
      // 通知 redux 执行加法
      dispatch(createDecrementAction(data))
    },
    jiaAsync: (data) => {
      // 通知 redux 执行加法
      dispatch(createIncrementAsyncAction(data, 500))
    },
  }
}

// 使用 connect()() 创建并暴露一个 Count 的容器组件
export default connect(mapStateToProps, mapDisapatchToProps)(CountUI)

UI 组件的写法:

jsx 复制代码
import React, { Component } from 'react'
export default class CountUI extends Component {
  // 加法
  increment = () => {
    const { value } = this.selectNo
    this.props.jia(value * 1)
  }
  // 减法
  decrement = () => {
    const { value } = this.selectNo
    this.props.jian(value * 1)
  }
  // 当前求和为奇数再加
  incrementIfOdd = () => {
    let { count } = this.props
    if (count % 2 !== 0) {
      this.increment()
    }
  }
  //异步加
  incrementAsync = () => {
    const { value } = this.selectNo
    this.props.jiaAsync(value * 1)
  }
  render() {
    console.log('props--->', this.props)
    return (
      <div>
        <h1>当前求和为:{this.props.count}</h1>
        <select
          ref={(c) => {
            this.selectNo = c
          }}
        >
          <option value="1">1</option>
          <option value="2">2</option>
          <option value="3">3</option>
        </select>&nbsp;&nbsp;
        <button onClick={this.increment}>加</button> &nbsp;&nbsp;
        <button onClick={this.decrement}>减</button>&nbsp;&nbsp;
        <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
        &nbsp;&nbsp;
        <button onClick={this.incrementAsync}>异步加</button>
      </div>
    )
  }
}

4.3 备注 1:容器组件中的 store 是靠 props 传递的,而不是容器组件中直接引入 store

4.4 备注 2:mapDispatchToProps 也可以是一个对象

react-redux 会将 action 进行分发,不再需要自己调用 dispatch

容器组件(自带监测功能)的优化写法:

jsx 复制代码
// 容器组件 react-redux

// 引入Count 的 UI 组件
import CountUI from '../../components/Count'
// 引入 action
import {
  createIncrementAction,
  createDecrementAction,
  createIncrementAsyncAction,
} from '../../redux/count_action'

// 引入 connect 用于连接 UI 组件与 redux
import { connect } from 'react-redux'

// 使用 connect()() 创建并暴露一个 Count 的容器组件
export default connect(
  (state) => ({ count: state }),
  /*
  // mapDispatchToProps 的一般写法
  dispatch=>{
    return  {
      jia: (data) =>{
          // 通知 redux 执行加法
        dispatch(createIncrementAction(data))
      },
      jian: (data) =>{
        // 通知 redux 执行加法
        dispatch(createDecrementAction(data))
      },
      jiaAsync: (data) =>{
        // 通知 redux 执行加法
        dispatch(createIncrementAsyncAction(data, 500))
      },
    }
  }
  */
  // mapDispatchToProps 的简写,
  {
    jia: createIncrementAction, // react-redux 会将action进行分发,不再需要自己调用 dispatch
    jian: createDecrementAction,
    jiaAsync: createIncrementAsyncAction,
  },
)(CountUI)

容器组件里面的 store 从哪里得到的?------

5、求和案例_react-redux 优化

1、容器组件和 UI 组件混成一个文件

2、无需自己给容器组件传递 store,给 包裹一个 Provider store={store} 即可

3、使用了 react-redux 后也不用自己监测 redux 中状态的改变了,容器组件可以自动完成这个工作

4、mapDispatchToProps 也可以简单的写成一个对象

5、一个组件要和 redux "打交道"要警告过哪几步?

(1)定义 UI 组件 --- 不暴露

(2)引入 connect 生成一个容器组件并暴露,写法如下:

jsx 复制代码
connect(
  state=>(key:value),// 映射状态
  {key: xxxxAction}//映射操作状态的方法
)(UI 组件)

(3)在 UI 组件中通过 this.props.xxx 读取和操作状态

6、多组件共享数据_redux 管理

1、定义一个 Person 组件,和 Count 组件通过 redux 共享数据

2、为 Person 组件编写:reducer、action ,配置 constant 常量

3、重点:Person 的 reducer 和 Count 的 reducer 要使用 combineReducers 进行合并,合并后的总状态时一个对象!!!

4、交给 store 的时总 reducer,最后注意在组件中取出状态的时候,记得"取到位"

jsx 复制代码
export default connect(
  (state) => ({
    sum: state.sum,
    personList: state.personList,
  }),
  {
    jia: createIncrementAction,
  },
)(Count)

Count 组件的 action

jsx 复制代码
/**
 * 该文件专门为 Count 组件生成 action 对象
 */
import { INCREMENT, DECREMENT } from '../constant'
export const createIncrementAction = (data) => {
  return {
    type: INCREMENT,
    data,
  }
}
// 同步 action,返回一般对象。同步 action 的值为 Object 类型的一般对象
export const createDecrementAction = (data) => ({
  type: DECREMENT,
  data,
})
// 异步action ,返回 函数。 异步action 就是指 action 的值为函数。异步action 中一般都会调用同步 action
export const createIncrementAsyncAction = (data, time) => {
  return (dispatch) => {
    console.log(dispatch, 'dispatch')
    setTimeout(() => {
      dispatch(createIncrementAction(data))
    }, time)
  }
}
// 数组和数字都不能够开启 异步任务,所以不会定义这些类型为异步 action

7、纯函数

1、一类特别的函数:只要是同样的输入(实参),必定得到同样的输出(返回)

2、必须遵守以下一些约束

(1)不得改参数数据

(2)不会产生任何副作用,例如网络请求,输入和输出设备

(3)不能调用 Date.now() 或者 Math.random() 等不纯的方法

3、redux 的 reducer 函数必须是一个纯函数(不能写 unshift 等方法添加数据,如果 preState 被改写 reducer 就不纯了,页面也不会更新)!!!

8、Redux 开发者工具 redux-devtool

1、安装开发者工具

2、安装依赖(配合插件使用)

npm i redux-devtools-extension

3、store 中引入

jsx 复制代码
import { composeWithDevTools } from 'redux-devtools-extension'
export default createStore(
  allReducer,
  composeWithDevTools(applyMiddleware(thunk)),
)

store.js 完整代码

jsx 复制代码
/**
 * 该文件专门用于暴露一个store 对象,整个应用只有一个 store 对象
 */
// 引入createStore,专门用于创建 redux 中最为核心的是store 对象
import { applyMiddleware, createStore, combineReducers } from 'redux'

// 引入 redux-thunk 用于支持异步action
import thunk from 'redux-thunk'

// 引入为 Count 组件服务的reducer
import countReducer from './reducers/count'
import personReducer from './reducers/person'
import { composeWithDevTools } from 'redux-devtools-extension'

// 汇总所有的 reducer 变成一个总的 reducer
const allReducer = combineReducers({
  sum: countReducer,
  personList: personReducer,
})

export default createStore(
  allReducer,
  composeWithDevTools(applyMiddleware(thunk)),
)

五、项目打包运行

npm run build

使用 serve 插件可以在本地开启一个本地服务器,使用命令 serve 就可以启动当前的文件夹
npm i serve -g

项目资源文件

相关推荐
繁依Fanyi1 小时前
828华为云征文|华为Flexus云服务器搭建OnlyOffice私有化在线办公套件
服务器·开发语言·前端·python·算法·华为·华为云
叫我小鹏呀1 小时前
vue3中el-table中点击图片放大时,被表格覆盖
前端·javascript·vue.js
我命由我123451 小时前
2.使用 VSCode 过程中的英语积累 - Edit 菜单(每一次重点积累 5 个单词)
前端·javascript·ide·vscode·学习·编辑器·学习方法
四季予你661 小时前
vue2 和 vue3 的区别
前端·javascript·vue.js
炒毛豆2 小时前
vue3+ant design vue实现可编辑表格弹出气泡弹出窗~
前端·javascript·vue.js
寰宇软件2 小时前
vue组件注册
前端·javascript·vue.js
OEC小胖胖2 小时前
js进阶-作用域是什么
开发语言·前端·javascript·ecmascript·web
东方翱翔2 小时前
HTML中的文字与分区标记
java·前端·html
职场人参3 小时前
将多个pdf合并成一个文件?这几种合并方法很好用!
linux·前端·css
小彭努力中3 小时前
20. gui调试3-下拉菜单、单选框
前端·3d·webgl