Blog
首页
文档
收藏
关于
  • 在线转换时间戳 (opens new window)
  • 在线压缩图片 (opens new window)
  • Float-Double转二进制 (opens new window)
  • 文件转Hex字符串 (opens new window)

HiuZing

🍑
首页
文档
收藏
关于
  • 在线转换时间戳 (opens new window)
  • 在线压缩图片 (opens new window)
  • Float-Double转二进制 (opens new window)
  • 文件转Hex字符串 (opens new window)
  • 前端面试题

  • JavaScript

  • Vue2

  • port

  • CSS

  • Node.js

  • JavaScript优化

  • uniapp

  • Mini Program

  • TypeScript

  • 面向对象编程

  • UI组件

  • Plugin

  • Vue3

  • 性能优化

  • Axios

  • 状态管理

  • React

    • 教程

      • React 简介
      • React 组件
      • React 应用
      • React AJAX
      • React Router5
      • React Redux
        • 理解
          • 文档
          • redux是什么
          • 什么情况下需要使用redux
        • redux的三个核心概念
          • action
          • reducer
          • store
        • 精简流程
        • 完整流程
        • redux的核心API
        • redux异步编程
        • react-redux
          • react-redux基本版
          • react-redux优化版
        • react-redux数据共享
        • redux调试工具
        • react-redux最终版
      • React 扩展内容
      • React Router6
      • React Router Hooks
      • React Hooks
    • 实战

  • Mock

  • Icon

  • Template

  • 构建工具

  • 项目规范配置

  • Taro

  • SVG

  • React Native

  • 前端
  • React
  • 教程
HiuZing
2023-05-03
目录

React Redux

# 理解

# 文档

英文文档: https://redux.js.org/ 中文文档: http://www.redux.org.cn/ Github: https://github.com/reactjs/redux

# redux是什么

  1. redux是一个专门用于做状态管理的JS库(不是react插件库)。
  2. 它可以用在react, angular, vue等项目中, 但基本与react配合使用。
  3. 作用: 集中式管理react应用中多个组件共享的状态。

# 什么情况下需要使用redux

  1. 某个组件的状态,需要让其他组件可以随时拿到(共享)。
  2. 一个组件需要改变另一个组件的状态(通信)。
  3. 总体原则:能不用就不用, 如果不用比较吃力才考虑使用。

# redux工作流程

image-20230503162041914

# redux的三个核心概念

# action

  1. 动作的对象
  2. 包含2个属性
    1. type:标识属性, 值为字符串, 唯一, 必要属性
    2. data:数据属性, 值类型任意, 可选属性
  3. 例子:{ type: 'ADD_STUDENT',data:{name: 'tom',age:18} }

# reducer

  1. 用于初始化状态、加工状态。
  2. 加工时,根据旧的state和action, 产生新的state的纯函数。

# store

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

  2. 如何得到此对象?

    import {createStore} from 'redux'
    import reducer from './reducers'
    const store = createStore(reducer)
    
    1
    2
    3
  3. 此对象的功能?

    // 得到state
    getState():
    // 分发action, 触发reducer调用, 产生新的state
    dispatch(action)
    // 注册监听, 当产生了新的state时, 自动调用
    subscribe(listener)
    
    1
    2
    3
    4
    5
    6

# 精简流程

求和案例

创建redux文件夹-创建store.js-暴露store-创建reducer.js-在组件引入sore使用-获取state-dispatch方法通知store-订阅redux状态重新渲染。

  1. src下建立:

​ -redux

​ -store.js

​ -count_reducer.js

  1. store.js:

    1. 引入redux中的createStore函数,创建一个store
    2. createStore调用时要传入一个为其服务的reducer
    3. 暴露store对象
  2. count_reducer.js:

    1. reducer的本质是一个函数,接收:preState,action,返回加工后的状态
    2. reducer有两个作用:初始化状态,加工状态
    3. reducer被第一次调用时,是store自动触发的,传递的preState是undefined,传递的action是:{type:'@@REDUX/INIT_a.2.b.4}
  3. 在index.js中监测store中状态的改变,一旦发生改变重新渲染

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

# 完整流程

求和案例

在以上的基础上新增文件:

  1. count_action.js 专门用于创建action对象
  2. constant.js 放置容易写错的type值
    //该文件专门用于暴露一个store对象,整个应用只有一个store对象
    
    //引入createStore,专门用于创建redux中最为核心的store对象
    import {createStore} from 'redux'
    //引入为Count组件服务的reducer
    import countReducer from './count_reducer'
    //暴露store
    export default createStore(countReducer)
    
    1
    2
    3
    4
    5
    6
    7
    8
    //该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错
    
    export const INCREMENT = 'increment'
    export const DECREMENT = 'decrement'
    
    1
    2
    3
    4
    import React, { Component } from 'react'
    //引入store,用于获取redux中保存状态
    import store from '../../redux/store'
    //引入actionCreator,专门用于创建action对象
    import {createIncrementAction} from '../../redux/count_action'
    
    export default class Count extends Component {
      //加法
      increment = ()=>{
      	const {value} = this.selectNumber
      	store.dispatch(createIncrementAction(value*1))
      }
      render() {
      	return (
      		<div>
      			<h1>当前求和为:{store.getState()}</h1>
      			<select ref={c => this.selectNumber = c}>
      				<option value="1">1</option>
      			</select>
      			<button onClick={this.increment}>+</button>
      		</div>
      	)
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // 该文件专门为Count组件生成action对象
    import {INCREMENT,DECREMENT} from './constant'
    
    export const createIncrementAction = data => ({type:INCREMENT,data})
    
    1
    2
    3
    4
    // 1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
    // 2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
    
    import {INCREMENT,DECREMENT} from './constant'
    
    const initState = 0 //初始化状态
    export default function countReducer(preState=initState,action){
      // console.log(preState);
      //从action对象中获取:type、data
      const {type,data} = action
      //根据type决定如何加工数据
      switch (type) {
      	case INCREMENT: //如果是加
      		return preState + data
      	case DECREMENT: //若果是减
      		return preState - data
      	default:
      		return preState
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // 重新渲染
    store.subscribe(() => {
      root.render(
        <App/>
      )
    })
    
    1
    2
    3
    4
    5
    6
    // Make sure to add code blocks to your code group

    # redux的核心API

    # redux异步编程

    1. 明确:延迟的动作不想交给组件自身,想交给action(redux默认是不能进行异步处理的,)

    2. 何时需要异步action:想要对状态进行操作,但是具体的数据靠异步任务(ajax, 定时器)返回。

    3. 具体编码:

      1. 使用异步中间件,npm install --save redux-thunk,并配置在store中
      2. 创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务。
      3. 异步任务有结果后,分发一个同步的action去真正操作数据。
    4. 备注:异步action不是必须要写的,完全可以自己等待异步任务的结果了再去分发同步action。

      //引入createStore,专门用于创建redux中最为核心的store对象
      import {createStore,applyMiddleware} from 'redux'
      //引入为Count组件服务的reducer
      import countReducer from './count_reducer'
      //引入redux-thunk,用于支持异步action
      import thunk from 'redux-thunk'
      //暴露store
      export default createStore(countReducer,applyMiddleware(thunk))
      
      1
      2
      3
      4
      5
      6
      7
      8
      incrementAsync = ()=>{
          const {value} = this.selectNumber
          // setTimeout(()=>{
          store.dispatch(createIncrementAsyncAction(value*1,500))
          // },500)
      }
      
      1
      2
      3
      4
      5
      6
      // 所谓异步action,就是指action的值为函数,异步action中一般都会调用同步action
      export const createIncrementAsyncAction = (data, time) => {
      //这里能接收dispatch,因为该函数是store调用,因此store就知道是要用到dispatch,就帮传过来了
      return (dispatch) => {
        setTimeout(() => {
          dispatch(createIncrementAction(data))
        },time)
      }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      // Make sure to add code blocks to your code group

      # react-redux

      与redux相比,redux文件内没有变化

      # react-redux基本版

      1. 概念:

        1. UI组件:不能使用任何redux的api,只负责页面的呈现、交互等。
        2. 容器组件:负责和redux通信,将结果交给UI组件。
      2. 如何创建一个容器组件————靠react-redux的 connect函数

        1. connect(mapStateToProps,mapDispatchToProps)(UI组件)

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

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

      3. 备注1:容器组件中的store是靠props传进去的,而不是在容器组件中直接引入

      4. 备注2:mapDispatchToProps,也可以是一个对象

        import {createStore,applyMiddleware} from 'redux'
        import countReducer from './count_reducer'
        import thunk from 'redux-thunk'
        export default createStore(countReducer,applyMiddleware(thunk))
        
        1
        2
        3
        4
        import {INCREMENT,DECREMENT} from './constant'
        const initState = 0
        export default function countReducer(preState=initState,action){
        	const {type,data} = action
        	switch (type) {
        		case INCREMENT:
        			return preState + data
        		case DECREMENT:
        			return preState - data
        		default:
        			return preState
        	}
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        import {INCREMENT,DECREMENT} from './constant'
        
        export const createIncrementAction = data => ({type:INCREMENT,data})
        
        1
        2
        3
        import Count from './containers/Count'
        import store from './redux/store'
        
        export default class App extends Component {
          render() {
          	return (
          		<div>
          			{/* 给容器组件传递store */}
          			<Count store={store} />
          		</div>
          	)
          }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        //引入Count的UI组件
        import CountUI from '../../components/Count'
        //引入action
        import {
          createIncrementAction,
        } 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用于传递状态
        */
        function mapStateToProps(state){
          return {count:state}
        }
        
        /* 
          1.mapDispatchToProps函数返回的是一个对象;
          2.返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value
          3.mapDispatchToProps用于传递操作状态的方法
        */
        function mapDispatchToProps(dispatch){
          return {
          	jia:number => dispatch(createIncrementAction(number)),
          }
        }
        
        //使用connect()()创建并暴露一个Count的容器组件
        export default connect(mapStateToProps,mapDispatchToProps)(CountUI)
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        import React, { Component } from 'react'
        
        export default class Count extends Component {
          //加法
          increment = ()=>{
          	const {value} = this.selectNumber
              // 通过props接收容器定义的方法
          	this.props.jia(value*1)
          }
          render() {
          	//console.log('UI组件接收到的props是',this.props);
          	return (
          		<div>
          			<h1>当前求和为:{this.props.count}</h1>
          			<select ref={c => this.selectNumber = c}>
          				<option value="1">1</option>
          			</select>&nbsp;
          			<button onClick={this.increment}>+</button>&nbsp;
          		</div>
          	)
          }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        // Make sure to add code blocks to your code group

        # react-redux优化版

        1. 无需自己给容器组件传递store,给App组件包裹一个Provider即可。
        2. 使用了react-redux后也不用再自己检测redux中状态的改变了,容器组件可以自动完成这个工作。
        3. mapDispatchToProps也可以简单的写成一个对象

        # react-redux数据共享

        1. 定义一个Person组件,和Count组件通过redux共享数据。
        2. 为Person组件编写:reducer、action,constant。
        3. 重点:Person的reducer和Count的Reducer要使用combineReducers进行合并,合并后的总状态是一个对象!

        # redux调试工具

        npm install --save-dev redux-devtools-extension
        
        1

        # react-redux最终版

        1. 在index中App组件外侧包裹Provider

        2. 在redux/index汇总了所有reducer文件(初始化),再一起在引入store

        3. 在actions文件定义好,能改变reducer状态的方法

        4. 在containers,定义好UI组件+容器组件

          1. 使用创建并暴露一个容器组件,通过

            connect(
                state => ({key:value}), //映射状态(reducer状态)
            	{key:xxxxxAction} //映射操作状态的方法(actions方法)
            )(UI组件)
            
            1
            2
            3
            4
          2. UI组件读取state通过this.props.xxxxxxx

        5. UI组件创建方法,里面调用容器组件引入的actions文件的方法

          // 引入react核心库
          import React from "react";
          // 引入createRoot
          import {createRoot} from "react-dom/client";
          import App from './App'
          import store from "./redux/store";
          import {Provider} from 'react-redux'
          
          const domNode = document.getElementById('root')
          const root = createRoot(domNode)
          root.render(
          //后代组件
          <Provider store={store}>
            <App/>
          </Provider>
          )
          
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          import React, {Component} from 'react';
          import Count from "./containers/Count"; // 引入容器组件
          import Person from "./containers/Person";
          
          class App extends Component {
          render() {
            return (
              <div>
                <Count/>
                <hr/>
                <Person/>
              </div>
            );
          }
          }
          
          export default App;
          
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          /* 
          	该文件专门用于暴露一个store对象,整个应用只有一个store对象
          */
          
          //引入createStore,专门用于创建redux中最为核心的store对象
          import {createStore,applyMiddleware} from 'redux'
          //引入汇总之后的reducer
          import reducer from './reducers'
          //引入redux-thunk,用于支持异步action
          import thunk from 'redux-thunk'
          //引入redux-devtools-extension
          import {composeWithDevTools} from 'redux-devtools-extension'
          
          //暴露store 
          export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))
          
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          /* 
          	该文件用于汇总所有的reducer为一个总的reducer
          */
          //引入combineReducers,用于汇总多个reducer
          import {combineReducers} from 'redux'
          //引入为Count组件服务的reducer
          import count from './count'
          //引入为Person组件服务的reducer
          import persons from './person'
          
          //汇总所有的reducer变为一个总的reducer
          export default combineReducers({
          	count,
          	persons
          })
          
          // redux/count
          /* 
          	1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
          	2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
          */
          import {INCREMENT,DECREMENT} from '../constant'
          
          const initState = 0 //初始化状态
          export default function countReducer(preState=initState,action){
          	// console.log('countReducer@#@#@#');
          	//从action对象中获取:type、data
          	const {type,data} = action
          	//根据type决定如何加工数据
          	switch (type) {
          		case INCREMENT: //如果是加
          			return preState + data
          		case DECREMENT: //若果是减
          			return preState - data
          		default:
          			return preState
          	}
          }
          
          // redux/person
          import {ADD_PERSON} from '../constant'
          
          //初始化人的列表
          const initState = [{id:'001',name:'tom',age:18}]
          
          export default function personReducer(preState=initState,action){
          	// console.log('personReducer@#@#@#');
          	const {type,data} = action
          	switch (type) {
          		case ADD_PERSON: //若是添加一个人
          			//preState.unshift(data) //此处不可以这样写,这样会导致preState被改写了,personReducer就不是纯函数了。
          			return [data,...preState]
          		default:
          			return preState
          	}
          }
          
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          36
          37
          38
          39
          40
          41
          42
          43
          44
          45
          46
          47
          48
          49
          50
          51
          52
          53
          54
          55
          56
          /* 
          	该文件专门为Count组件生成action对象
          */
          import {INCREMENT,DECREMENT} from '../constant'
          
          //同步action,就是指action的值为Object类型的一般对象
          export const increment = data => ({type:INCREMENT,data})
          export const decrement = data => ({type:DECREMENT,data})
          
          //异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
          export const incrementAsync = (data,time) => {
          	return (dispatch)=>{
          		setTimeout(()=>{
          			dispatch(increment(data))
          		},time)
          	}
          }
          
          /* 
          	该文件专门为Person组件生成action对象
          */
          import {ADD_PERSON} from '../constant'
          
          //创建增加一个人的action动作对象
          export const addPerson = personObj => ({type:ADD_PERSON,data:personObj})
          
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          import React, {Component} from 'react';
          
          // 引入connect用于连接UI组件与redux
          import {connect} from 'react-redux'
          import {decrement, increment, incrementAsync} from "../../redux/actions/count";
          
          class Count extends Component {
          state = {
            // count: 0
          }
          // 加法
          increment = () => {
            const {value} = this.selectNumber
            this.props.increment(value * 1)
          }
          decrement = () => {
            const {value} = this.selectNumber
            this.props.decrement(value * 1)
          
          }
          incrementIfOdd = () => {
            const {value} = this.selectNumber
            if (this.props.count % 2 !== 0) {
              this.props.increment(value * 1)
            }
          }
          incrementAsync = () => {
            const {value} = this.selectNumber
            this.props.incrementAsync(value * 1, 500)
          
          }
          
          render() {
            return (
              <div>
                <h2>我是Count组件</h2>
                <h1>当前求和为:{this.props.count},下方组件人数为:{this.props.personList}</h1>
                <select ref={c => this.selectNumber = c}>
                  <option value="1">1</option>
                  <option value="2">2</option>
                  <option value="3">3</option>
                </select>&nbsp;&nbsp;&nbsp;
                <button onClick={this.increment}>+</button>
                &nbsp;&nbsp;&nbsp;
                <button onClick={this.decrement}>-</button>
                &nbsp;&nbsp;&nbsp;
                <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
                &nbsp;&nbsp;&nbsp;
                <button onClick={this.incrementAsync}>异步加</button>
              </div>
            );
          }
          }
          
          // 使用connect()()创建并暴露一个Count的容器组件
          export default connect(
          state => ({count: state.count,personList:state.personList.length}),
          {
            increment,
            decrement,
            incrementAsync,
          }
          )(Count)
          
          // 
          
          import React, {Component} from 'react';
          import {nanoid} from 'nanoid'
          import {connect} from 'react-redux'
          import {addPerson} from "../../redux/actions/person";
          
          class Person extends Component {
          addPerson = () => {
            const name = this.nameNode.value
            const age = this.ageNode.value
            const personObj = {
              id: nanoid(),
              name,
              age
            }
            this.props.addPerson(personObj)
            this.nameNode.value = ''
            this.ageNode.value = ''
          }
          
          render() {
            return (
              <div>
                <h2>我是Person组件,上方组件求和为:{this.props.count}</h2>
                <input ref={c => this.nameNode = c} type="text" placeholder="输入名字"/>
                <input ref={c => this.ageNode = c} type="text" placeholder="输入年龄"/>
                <button onClick={this.addPerson}>添加</button>
                <ul>
                  {
                    this.props.personList.map((p)=>{
                      return <li key={p.id}>{p.name}--{p.age}</li>
                    })
                  }
                </ul>
              </div>
            );
          }
          }
          
          export default connect(
          state=>({personList:state.personList,count:state.count}),
          {addPerson}
          )(Person)
          
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          36
          37
          38
          39
          40
          41
          42
          43
          44
          45
          46
          47
          48
          49
          50
          51
          52
          53
          54
          55
          56
          57
          58
          59
          60
          61
          62
          63
          64
          65
          66
          67
          68
          69
          70
          71
          72
          73
          74
          75
          76
          77
          78
          79
          80
          81
          82
          83
          84
          85
          86
          87
          88
          89
          90
          91
          92
          93
          94
          95
          96
          97
          98
          99
          100
          101
          102
          103
          104
          105
          106
          107
          108
          // Make sure to add code blocks to your code group

          纯函数和高阶函数

          #React
          上次更新: 2024/08/14, 04:14:33
          React Router5
          React 扩展内容

          ← React Router5 React 扩展内容→

          最近更新
          01
          React Native 使用SVG
          08-13
          02
          Docker基础命令
          08-04
          03
          算数逻辑单元
          07-30
          更多文章>
          Theme by Vdoing | Copyright © 2021-2024 WeiXiaojing | 友情链接
          • 跟随系统
          • 浅色模式
          • 深色模式
          • 阅读模式