• redux基础第一讲


    在大型项目中,如果完全使用react管理数据将会是一件很麻烦的事情。这一章,我们将介绍如何使用redux来管理你的应用状态。

    Redux的基本原则

    我们知道,react的数据都是“单向数据流”,即由父组件往子组件一层一层的传递。redux在此基础上又强调了三个基本原则:

    • 唯一数据源
    • 保持状态只读
    • 数据改变只能通过纯函数完成
      下面,让我们具体分析这三条基本原则:

    唯一数据源

    整个应用只有一个store,所有组件的数据源就是这个store上的状态。这句话怎么理解呢?比如,我们要做一个博客系统,这个博客系统只有用户信息模块和显示博客列表模块。那么,store上的状态应该像下面这样设计:

    initState = {
        userInfo: ...,
        blogList: ...
    }
    

    initState.userInfo用来存储用户信息,initState.blogList用来存储博客信息。这样,我们就可以在一个store上存储所有的应用信息。

    保持状态只读

    不可直接修改状态,要通过派发一个action对象去完成修改。关于action,后面再做讲解。

    数据改变只能通过纯函数完成

    这里所说的純函数指的是就是reducer。那么何为純函数呢?純函数指的就是返回结果必须完全由参数决定,且不得修改参数值。

    reducer只负责计算state,并不负责存储state。存储state的工作交给Redux框架去做。在这里,你只需要知道当我们派发了一个action后,redux会根据action的type值,在reducer找到对应的条件分支,然后去处理这个分支下的行为,state的计算就在这个条件分之下完成。

    Redux实例

    下面,我们将创建一个简单的计数器应用来讲解具体该如何使用redux。应用界面的渲染必须通过state或props的改变来触发,而state或props的改变是用户操作行为导致的结果。上面说过,要修改状态需要派发一个action,这个action的派发,就是用户行为导致的。

    action

    action顾名思义代表一个“动作”,不过这个动作是一个普通的javascript对象。action对象必须有一个名为type的字段,代表这个action对象的类型。比如,计数器有加减操作,那么action的type可定义为'increment'或'decrement'。

    定义action通常需要两个文件,一个用于保存action的类型,一个用于创建action的构造函数。

    在ActionTypes.js文件中,我们定义action的类型。

    //  ActionTypes.js
    export const INCREMENT = 'increment';
    export const DECREMENT = 'decrement';
    

    上面分别定义了用户的两个动作,加和减。

    我们在actions.js中定义action的构造函数。注意,创建的是action构造函数,而不是action本身,action构造函数会返回一个action。

    // Actions.js
    import * as ActionTypes from './ActionTypes.js';
    
    export const increment = (counterCaption) => {
      return {
        type: ActionTypes.INCREMENT,
        counterCaption: counterCaption
      };
    };
    
    export const decrement = (counterCaption) => {
      return {
        type: ActionTypes.DECREMENT,
        counterCaption: counterCaption
      };
    };
    
    

    store

    action创建了之后,我们需要将它派发出去,以此来改变state。上面已经介绍过,state被存储在store,store提供dispatch()方法来派发action,dispatch接收action对象作为参数。

    我们先创建一个store.js文件,输出全局唯一的那个store。

    //  Store.js
    import {createStore} from 'redux';
    import reducer from './Reducer.js';
    
    const initValues = {
      'First': 0,
      'Second': 10,
      'Third': 20
    };
    const store = createStore(reducer, initValues);
    
    export default store;
    

    redux提供createStore方法来创建store。createStore方法接收两个参数,第一个参数代表更新状态的reducer,第二个参数是状态的初始值。关于createStore的具体用法,后面章节会介绍,这里只要知道这两个参数就行。

    reducer

    接下来创建reducer函数,reducer用于计算state。

    // Reducer.js
    import * as ActionTypes from './ActionTypes.js';
    
    export default (state, action) => {
      const {counterCaption} = action;
    
      switch (action.type) {
        case ActionTypes.INCREMENT:
          return {...state, [counterCaption]: state[counterCaption] + 1};
        case ActionTypes.DECREMENT:
          return {...state, [counterCaption]: state[counterCaption] - 1};
        default:
          return state
      }
    }
    

    在reducer函数中,根据action.type的判断条件来执行state的计算。上面的代码,我们使用了扩展运算符(...),不懂的同学自行补脑吧,在es6的课程有讲解。

    记住:reducer中绝对不能直接修改state。因为reducer是一个純函数,純函数的返回结果完全由传入的参数决定,且不可修改参数值。 使用扩展运算符,实际上复制了一个state副本,操作的是这个副本,犹如jquery中$.extend()的用法。

    view

    接下来,我们看一下view部分。view中有三个组件,最外层的是ControlPanel组件。

    // ControlPanel.js
    class ControlPanel extends Component {
        render() {
            return (
                <div style={style}>
                    <Counter caption="First"/>
                    <Counter caption="Second"/>
                    <Counter caption="Third"/>
                    <hr/>
                    <Summary/>
                </div>
            );
        }
    }
    

    ControlPanel组件中包含Counter和Summary两个组件,这里主要介绍Counter组件的写法,Summary组件和Counter组件写法差不多。

    首先初始化this.state

    // Counter.js
    class Counter extends Component {
      constructor(props) {
        super(props);
        ...
        
        this.state = this.getOwnState();
      }
    
      getOwnState() {
        return {
          value: store.getState()[this.props.caption]
        };
      }
      
      ...
    }
    

    我们把从store上获取状态的逻辑放在getOwnState()方法中,store.getState()可获得当前状态,也就是我们在Store.js中定义的initValues。

    为了保证store上的状态和this.state保持同步,需要监听store的变化。

    onChange() {
        this.setState(this.getOwnState());
    }
    componentDidMount() {
        store.subscribe(this.onChange);
    }
    componentWillUnmount() {
        store.unsubscribe(this.onChange);
    }
    

    在componentDidMount中。通过store.subscribe监听store变化,只要store发生变化,就会调用onChange方法;在componentWillUnmount函数中,我们把这个监听注销,和componentDidMount中的动作对应。

    改变store中状态的唯一方法是派发一个action。如下:

    // Counter.js
    class Counter extends Component {
      ...
      
      onIncrement() {
        store.dispatch(Actions.increment(this.props.caption));
      }
    
      onDecrement() {
        store.dispatch(Actions.decrement(this.props.caption));
      }
    
      ...
    
      render() {
        const value = this.state.value;
        const {caption} = this.props;
    
        return (
          <div>
            <button style={buttonStyle} onClick={this.onIncrement}>+</button>
            <button style={buttonStyle} onClick={this.onDecrement}>-</button>
            <span>{caption} count: {value}</span>
          </div>
        );
      }
    }
    
    

    store.dispatch()方法派发一个action后,redux会根据action的type值,查找在reducer函数中相符的判断条件来执行state的计算。

  • 相关阅读:
    前端的一些工具
    ubuntu安装intelij idea 和pycharm
    广义欧几里得算法,求解形如ax+by=c的整数解
    Kali安装jdk8
    ARP 项添加失败: 拒绝访问
    Python扩展包,解决”unable to find vcvarsall.bat“
    python实现mschap2
    Ubuntu 安装 Corsaro v2.0.0 全过程
    使用GridFS上传下载图片以及其他文件
    Eclipse设置工作空间编码
  • 原文地址:https://www.cnblogs.com/renzhiwei2017/p/9480910.html
Copyright © 2020-2023  润新知