React学习第八天(redux案例)

176 阅读5分钟

1.redux的使用

image.png

  1. 去除count自身的状态

  2. src下建立:

    • -src

      -reduc

      -store.js

      ​ -count_reducer.js

      目录结构

image.png

  1. Store.js

    • 引入redux中的createState函数,

    • 创建一个storecreateState调用是传入一个为其服务的reducer,

    • 记得暴露stoer对象

      代码:

      
      /**
       * 该文件专门用于暴露一个store对象,整个应用只有一个store对象
       */
      
      // 引入createStore 专门用于创建redux中最为核心的store对象
      import { createStore } from "redux";
      // 引入为count组件服务的reducer
      import countReducer from './count_reducer'
      
      // 暴露store
      export default createStore(countReducer);
      
      
  2. Count_reducer.js

    • reducer的本质是一个函数,接收preState,action,返回处理后的状态

    • reducer的两个作用:初始化数据,处理数据

    • reducer被第一次调用时,时store自动触发的,传递的preState时dudefined

      代码:

      /**
       * 初始化状态
       * 加工状态
       *
       *
       * 1.该文件就是用于创建一个为count服务的reducer,reducer的本质就是一个函数
       * 2.reducer接收两个参数,分别为:之前的状态(preState),动作对象(action)
       */
      
      export default function countReducer(preState = 100, action) {
        let { type, data } = action;
        switch (type) {
          case "increment": //处理加
            return preState + data;
          case "decrement": //处理减
            return preState - data;
          default:
            //不处理的话直接返回初始化数据
            return preState;
        }
      }
      
      
  3. 在index.js中检测store状态的改变,一旦发生改变重新渲染

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

    index.js 文件里面加入下列代码

    import store from './redux/store'
    store.subscribe(() => {
      ReactDOM.render(
        <BrowserRouter>
          <App />
        </BrowserRouter>,
        document.getElementById("root")
      ); //只要redux数据更新 就会触发render的更新
    });
    

    求和案例redux完整版本

新增文件

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

    /**
     * 该文件专门为count组件生成action对象
     */
    import { INCREMENT, DECREMENT } from "./constant";
    // 加法
    const createIncrementAction = (data) => ({ type: INCREMENT, data }); //返回一个对象
    // 减法
    const createDecrementAction = (data) => ({ type: DECREMENT, data });
    
    export { createIncrementAction, createDecrementAction };
    
    
  2. constant.js 放置容易写错的type

    /**
     * 该模块是用于定义action对象中type类型的常量值,目的:便于管理的同时防止程序员写错单词
     */
    
    export const INCREMENT = "increment";
    export const DECREMENT = "decrement";
    
    

求和案例redux异步action版

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

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

  3. 具体编码:

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

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

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

      //异步执行,就是指action返回的值为函数,异步action中一般都会调用同步action,非必须使用
      const createIncrementAsyncAction = (data, time) => {
        return (dispath) => {
          setTimeout(() => {
            dispath(createIncrementAction(data)); //在异步方法里面调用同步方法
          }, time);
        };
      };
      
  4. 备注:异步action不是必须要写的,完全可以自己等待异步任务的结果了再去分发同步action

    求和案例react-redux的基本使用

    1. 明确两个概念

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

      • connect(mapStateToProps, mapDispatchToProps)(UI组件);

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

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

        容器页面代码展示:

        // 引入ui组件
        import AddRedux from "../../view/AddRedux";
        //引入connect用于链接ui组件和redux
        import { connect } from "react-redux";
        //引入action
        import {
          createIncrementAction,
          createIncrementAsyncAction,
          createDecrementAction,
        } from "../../redux/count_action";
        
        /**
         * mapStateToProps返回的是一个对象
         * 1.返回的对象中的key就作为传递给ui组件props的key
         * 2.value就作为传递给ui组件props的value
         * 3.mapStateToProps用于传递状态
         *
         * @param {*} state
         * @returns
         */
        const mapStateToProps = (state) => {
          return { count: state };
        };
        
        /**
         *
         * * mapDispatchToProps返回的是一个对象
         * 1.返回的对象中的key就作为传递给ui组件props的key
         * 2.value就作为传递给ui组件props的value
         * 3.mapDispatchToProps用于操作状态的方法
         * @param {*} dispatch
         * @returns
         */
        const mapDispatchToProps = (dispatch) => {
          return {
            add: (data) => dispatch(createIncrementAction(data)), //通知redux执行加法
            sub: (data) => dispatch(createDecrementAction(data)),
            addAsync: (data) => dispatch(createIncrementAsyncAction(data, 1000)),
          };
        };
        // 使用connect()()创建并暴露一个Count的容器组件
        export default connect(mapStateToProps, mapDispatchToProps)(AddRedux);
        
        

        mapStateToPropsmapDispatchToProps的简化写法 (mapDispatchToProps也可以是一个对象)

        export default connect(
          (state) => ({ count: state }), //简写方法
          {
            //简化写法 react-redux内置api自动分发dispatch
            add: createIncrementAction, //通知redux执行加法
            sub: createDecrementAction,
            addAsync: createIncrementAsyncAction,
          }
        )(AddRedux);
        
    3. 备注:容器组件中的store是靠props传进去的,而不是容器组件中直接引入

      使用容器页面直接引入容器组件和store文件

      import Count from "./containers/Count";
      import store from "./redux/store";
      
      
       <div className="App">
            {/* 给容器组件传递store */}
            <Count store={store} />
       </div>
      

      求和案例react-redux优化

      1. 容器组件和UI组件整合一个文件

      2. 无需自己给容器组件传递store,给包裹一个Provider

         <Provider store={store}>
            <BrowserRouter>
              <App />
            </BrowserRouter>
          </Provider>,
        
      3. 使用react-redux不需要再监测redux更新状态,react-redux可以自动监测更新页面

      4. mapDispatchToProps可以写成对象

      5. 一个组件要和redux “打交道”要经过那几个步骤

        • 定义ui组件
        • 引入connect生成一个容器组件,并暴露
        • 在ui组件中通过this.props.xxxx读取和操作状态
      6. 容器组件和ui组件整合

        import React, { Component } from "react";
        import { Button, Select } from "antd";
        //引入connect用于链接ui组件和redux
        import { connect } from "react-redux";
        //引入action
        import {
          createIncrementAction,
          createIncrementAsyncAction,
          createDecrementAction,
        } from "../../redux/count_action";
        
        
        
        const { Option } = Select;
        class AddRedux extends Component {
          state = {
            initVal: 0,
            selectArr: [1, 2, 3, 4, 5, 6, 7],
            selectVal: 1,
          };
        
          //   加
          increment = () => {
            let { selectVal } = this.state;
        
            this.props.add(selectVal);
          };
          sub = () => {
            let { selectVal } = this.state;
            this.props.sub(selectVal);
          };
        
          mul = () => {
            let { selectVal } = this.state;
            let { count } = this.props;
            if (count % 2 != 0) {
              this.props.add(selectVal);
            }
          };
        
          division = () => {
            let { selectVal } = this.state;
            this.props.addAsync(selectVal,1000);
          };
          selectChange = (val) => {
            console.log(val);
            this.setState({
              selectVal: val,
            });
          };
        
          render() {
            console.log(this.props, "react-redux");
            let { initVal, selectArr, selectVal } = this.state;
            return (
              <div style={{ margin: "20px" }}>
                <h1>初始值:{this.props.count}</h1>
        
                <Select
                  value={selectVal}
                  style={{ width: "32%", margin: "10px" }}
                  onChange={this.selectChange}
                >
                  {selectArr.map((item) => {
                    return (
                      <Option value={item} key={item}>
                        {item}
                      </Option>
                    );
                  })}
                </Select>
                <br />
                <Button
                  type="primary"
                  style={{ margin: "0 10px" }}
                  onClick={() => this.increment()}
                >
                  +
                </Button>
                <Button
                  type="primary"
                  style={{ margin: "0 10px" }}
                  onClick={() => this.sub()}
                >
                  -
                </Button>
                <Button
                  type="primary"
                  style={{ margin: "0 10px" }}
                  onClick={() => this.mul()}
                >
                  当前就和为奇数再加
                </Button>
                <Button
                  type="primary"
                  style={{ margin: "0 10px" }}
                  onClick={() => this.division()}
                >
                  异步加
                </Button>
              </div>
            );
          }
        }
        export default connect(
          (state) => ({ count: state }), //简写方法
          {
            //简化写法 react-redux内置api自动分发dispatch
            add: createIncrementAction, //通知redux执行加法
            sub: createDecrementAction,
            addAsync: createIncrementAsyncAction,
          }
        )(AddRedux);