美文网首页
Flux => Redux

Flux => Redux

作者: learninginto | 来源:发表于2020-05-08 23:09 被阅读0次

    Flux => Redux

    上一篇文章中,提到了React中的Flux架构,尽管理解起来相对容易,但是随着项目体系的增加,需要实时地将容器组件(处理页面逻辑)与UI组件(负责页面渲染)分离,手动地来降低各个模块之间的耦合度。

    而Redux的出现,解决了过于复杂地拆分,可以更高效地管理多个store,并且不需要对每个视图更新函数做绑定。

    • Redux的设计思想
    1. Web 应用是一个状态机,视图与状态是一一对应的。

    2. 所有的状态,保存在一个对象里面(唯一数据源)。

    注意:flux、redux都不是必须和react搭配使用的,因为flux和redux是完整的架构,在学习react的时候,只是将react的组件作为redux中的视图层去使用了。

    一、为什么要使用Redux

    简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。

    • 需要使用Redux的项目
    1. 用户的使用方式复杂
    2. 不同身份的用户有不同的使用方式(比如普通用户和管理员)
    3. 多个用户之间可以协作
    4. 与服务器大量交互,或者使用了WebSocket
    5. View要从多个来源获取数据
    • 从组件层面考虑是否需要Redux
    1. 个组件的状态,需要共享
    2. 某个状态需要在任何地方都可以拿到
    3. 一个组件需要改变全局状态
    4. 一个组件需要改变另一个组件的状态
    • Redux使用的三大原则
    1. Single Source of Truth(唯一的数据源)
    2. State is read-only(状态是只读的)
    3. Changes are made with pure function(数据的改变必须通过纯函数完成)

    二、快速上手

    redux.png

    当组件要修改数据的时候,通过ActionCreators中的dispatch发送action给store,但是store的内部将action传递给了reducers,reducers进行了数据的更改,将新的state返回给store,由于store中的数据中响应式的,最后通过store通知view再次更新视图。

    • 安装
    cnpm i redux -S
    
    • createStore函数,专门用来创建公共的内存空间store,将这里的数据渲染到页面上。

    store是一个对象,里面有几个常用的函数:getState / dispatch / subscribe

    参数:回调函数reducers

    import {createStore} from "redux";
    import reducers from "./reducers"
    const store = createStore(reducers);
    
    export default store;
    
    • reducer.js
    1. 必须是一个纯函数(输入一定,输出也一定),函数中有两个参数:1. state 2. action;Redux为了防止报错,默认给了参数初始值 。

    2. 当前函数必须有一个默认的state

    3. 纯函数内部的state只允许读,不允许修改

    4. 不能调用系统 I/O 的API

    5. 当前函数必须要返回一个state,返回的state会替换原来的state

      state = reduce(state , action)

    //存储初始的数据
    const defaultState = {
        n:10
    }
    
    export default (state=defaultState,action)=>{
        switch(action.type){
            case "NUM_ADD":
              var numState = JSON.parse(JSON.stringify(state));
              numState.n++;
              return numState;
        }
        return state
    }
    
    • App.js
    import React, { Component } from 'react'
    import store from "./store"
    
    export default class App extends Component {
      constructor() {
        super();
        this.state = store.getState();
        store.subscribe(this.handleUpdate.bind(this))
      }
      render() {
    
        let { n } = this.state;
        return (
          <div>
            <h2>{n}</h2>
            <button onClick={this.handleClick.bind(this)}>点击</button>
          </div>
        )
      }
      handleClick() {
        var action = {
          type: "NUM_ADD"
        }
        store.dispatch(action);
      }
      handleUpdate() {
        this.setState(store.getState())
      }
    }
    

    三、combineRedux

    因为一个应用中只能有一个大的state,这样的话reducer中的代码将会特别多。简单概括,该方法用来合并多个reducers

    • 注意
    1. 分离reducer的时候,每一个reducer维护的状态都应该不同
    2. 通过store.getState获取到的数据也是会按照reducers去划分的
    3. 划分多个reducer的时候,默认状态只能创建在reducer中,因为划分reducer的目的,就是为了让每一个reducer都去独立管理一部分状态
    • 安装
    cnpm i redux-devtools-extension -D
    
    • 引入
    import { createStore, combineReducers } from "redux"
    import { composeWithDevTools } from "redux-devtools-extension";
    
    • combineReducers合并多个reducers
    import { createStore, combineReducers } from "redux";
    import { composeWithDevTools } from 'redux-devtools-extension';
    //combineReducers 合并多个reducers
    import num from "./reducers/num"
    import todo from "./reducers/todo"
    
    const reducers = combineReducers({
        num,
        todo
    })
    const store = createStore(reducers, composeWithDevTools());
    
    export default store;
    

    四、Redux封装

    • store/index.js

    store中要返回一个对象,包含三个常用的方法getState/dispatch/subscribe

    import { createStore, combineReducers } from "../redux/index"
    import num from "./reducers/num"
    import todo from "./reducers/todo"
    
    const reducers = combineReducers({
        num,
        todo
    })
    const store = createStore(reducers);
    
    //store应该是一个对象  getState dispatch  subscribe
    export default store;
    
    • store/reducer/num.js

    这里的state要有默认值defaultState,没有时为undefined(注意:不能赋值为null)

    const defaultState = {
        n: 10
    }
    export default (state = defaultState, action) => {
        switch (action.type) {
            case "NUM_ADD":
                var numState = Object.assign({}, state);
                numState.n++;
                return numState;
        }
        return state;
    }
    
    • redux/index.js

    上面的action中默认有一个初始值。

    getState返回state值;

    subscribe监听eventList中的函数;

    dispatch接收action,传入state和action触发reducer处理逻辑

    var initAction = { type: "@@/redux" }
    
    export const createStore = (reducer) => {
    
        let eventList = [];
        let state = {};//默认为undefined
    
        // 返回state
        let getState = () => state;
        // 监听eventList中的函数
        let subscribe = (callback) => {
            eventList.push(callback);
        }
    
        let dispatch = (action) => {
            state = reducer(state, action);
            eventList.forEach(cb => {
                cb();
            })
        }
    
        // dispatch第一次默认会调用
        dispatch(initAction);
    
        return {
            getState,
            subscribe,
            dispatch,
        }
        
        //combineReducers的返回值是一个函数
        export const combineReducers = (reducers)=>{
            var newState = {};
            return (state,action)=>{
                for(var key in reducers){
                    newState[key] = reducers[key](state[key],action);
                }
                return newState;
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Flux => Redux

          本文链接:https://www.haomeiwen.com/subject/xpecnhtx.html