手拉手学React:Redux

2019-02-08  本文已影响0人  曽小晨

redux中文网

何为Redux

Redux 是 JavaScript 状态容器,用来存储项目中一些公共的数据,做到数据“一处存储,多处取出”的事情,跟 Vue 的 Vuex 属于一类角色。

它的诞生是为了解决用 React 开发大型项目中解决不了难题。如果你的项目中组件繁多,而且组件之间的通信又必不可少,这个时候 Redux 能很好的解决这个问题。

举个例子,原本组件通信是只有父子通信,如果爷孙俩通信就需要借助“父”来实现:

没有Redux时的组件通信

问题就在于,如果组件非常多,数以千计,再通信性能就非常低,而且也不方便。那这个时候,把大家都需要的数据放在一个公共的地方,谁要谁就去取:

有Redux的通信

这样,不管有多少个组件、组件的层次有多深,都能快速的拿到需要拿的数据。

Redux 工作流程

开篇一张图,内容全靠编:

image

Store 就相当于一个房地产中介一样,我们想要一个地区的所有房源信息,就需要通过它来获取,Reducers 是幕后人,中介的信息来源都是Reducers告诉它的,比喻成一个“房产资源手册”可能更合适。

中介给了用户三个行为:

介绍完这些之后,咱们把整个流程串一下:

这中间也有一些限制,比如action必须拥有type字段,其他属性可能由用户自定义,reducer是一个纯函数,应当遵循纯函数的一些设计理念。

不得改写参数。
不能有异步操作。
不能调用Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果。(引用自阮一峰

雇佣中介,自当用户

现在咱们用代码完成以上所述,第一步是需要有中介(store),才会有用户,所以先创建中介(store):

import { createStore } from 'redux';
import reducer from './reducer'; // 同时把房产资源手册(reducer)交给中介

const store = createStore(reducer);

export default store;
/**
 * 每次用户手动调用dispatch的时候,会自动调用这个方法
 *
 * <strong>这个方法只能接受state,绝不能修改state,这是明文限制!</strong>
 * @param {Object} state 上一个未改变的state
 * @param {Object} action 当前用户传递过来的action
 * @param {String} action.type action的类型,通过这个类型,得知用户需要改动哪个变量
 * @return {{inputValue: string, list: Array}}
 */
export default function (state = defaultState, action) {
    const newState = JSON.parse(JSON.stringify(state));
    if (action.type === 'CHANGE_INPUT_VALUE') {
        /** @namespace action.value */
        newState.inputValue = action.value;
    } else if (action.type === 'LIST_ADD') {
        newState.list.push(newState.inputValue);
        newState.inputValue = '';
    }
    return newState;
}

先不看房产资源手册(reducer)做了什么事情,第二步就是建立自己的用户(React Components):

import React, { Component } from 'react';
import 'antd/dist/antd.css';
import { Input, Button, List } from 'antd';
import store from '../store'; // 第一步:引入中介(store)

class Home extends Component {
    constructor(...args) {
        super(...args);
        this.state = store.getState(); // 第二步:得到全部房源信息
        store.subscribe(() => { // 第三步:这个用户(React components)需要第一时间知道房源的最新动向
            this.setState(store.getState());
        }); // 订阅store,store数据发生改变的时候需要做的事情,这个方法同时会返回一个方法,用来取消订阅
    }
    inputChange = (e) => {
        const action = {
            type: 'CHANGE_INPUT_VALUE',
            value: e.target.value
        };
        store.dispatch(action);
    };
    btnSubmit = () => {
        store.dispatch({
            type: 'LIST_ADD'
        }) // 第四步:升级为房东,通知中介(store)修改自己的房源信息,这里对应房产资源手册的代码逻辑
    };
    render() {
        return (
            <div style={{ margin: '10px' }}>
                <Input
                    value={this.state.inputValue}
                    placeholder="Basic usage"
                    style={{ width: '300px' }}
                    onChange={this.inputChange}
                />
                <Button type="primary" style={{ marginLeft: '10px' }} onClick={this.btnSubmit}>提交</Button>
                <List
                    style={{ marginTop: '10px', width: '300px' }}
                    bordered
                    dataSource={this.state.list}
                    renderItem={item => (<List.Item>{item}</List.Item>)}
                />
            </div>
        );
    }
}

export default Home;

代码优化

需要将上面action.type值单独提出来放在一个常量文件里,组件中和reducer里就更不容易出错。

统一创建action

// actionCreateor.js
const defaultField = 'value'; // action默认的扩展字段
/**
 * 统一创建action
 * @param {String} type 类型
 * @param {any} value 值
 */
export function createAction(type, value) {
    if (!type) throw new Error('【非法参数】type必须是一个合法的参数值,当前type值是:' + type);
    let action = { type };
    switch (typeof value) {
        case 'object': {
            action = Object.assign(action, value);
            break;
        }
        default: {
            action[defaultField] = value;
        }
    }
    return action;
}
上一篇下一篇

猜你喜欢

热点阅读