redux原理了解

一、为何要用redux

在React中,数据在组件中是单向流动的,数据从一个方向父组件流向子组件(经过props),因此,两个非父子组件之间通讯就相对麻烦,redux的出现就是为了解决state里面的数据问题javascript

二、Redux设计理念

Redux是将整个应用状态存储到一个地方上称为store,里面保存着一个状态树store tree,组件能够派发(dispatch)行为(action)给store,而不是直接通知其余组件,组件内部经过订阅store中的状态state来刷新本身的视图。css


三、Redux三大原则

  • 1 惟一数据源
  • 2 保持只读状态
  • 3 数据改变只能经过纯函数来执行

1惟一数据源

整个应用的state都被存储到一个状态树里面,而且这个状态树,只存在于惟一的store中html

2保持只读状态

state是只读的,惟一改变state的方法就是触发action,action是一个用于描述以发生时间的普通对象java

3数据改变只能经过纯函数来执行

使用纯函数来执行修改,为了描述action如何改变state的,你须要编写reducersredux

或许你读到这已经不知所云了,没事这只是让你了解一些redux究竟是干吗的,后面或详细的讲解各个部分的做用,而且会讲解redux实现原理bash

四、Redux概念解析

4.1 Store

  • store就是保存数据的地方,你能够把它当作一个数据,整个应用智能有一个store
  • Redux提供createStore这个函数,用来生成Store
import {createStore} from 'redux'
const store=createStore(fn);
复制代码

4.2 State

state就是store里面存储的数据,store里面能够拥有多个state,Redux规定一个state对应一个View,只要state相同,view就是同样的,反过来也是同样的,能够经过store.getState( )获取markdown

import {createStore} from 'redux'
const store=createStore(fn);
const state=store.getState()
复制代码

4.3 Action

state的改变会致使View的变化,可是在redux中不能直接操做state也就是说不能使用this.setState来操做,用户只能接触到View。在Redux中提供了一个对象来告诉Store须要改变state。Action是一个对象其中type属性是必须的,表示Action的名称,其余的能够根据需求自由设置。app

const action={
  type:'ADD_TODO',
  payload:'redux原理'
}
复制代码

在上面代码中,Action的名称是ADD_TODO,携带的数据是字符串‘redux原理’,Action描述当前发生的事情,这是改变state的惟一的方式函数

4.4 store.dispatch( )

store.dispatch( )是view发出Action的惟一办法ui

store.dispatch({
  type:'ADD_TODO',
  payload:'redux原理'
})
复制代码

store.dispatch接收一个Action做为参数,将它发送给store通知store来改变state。

4.5 Reducer

Store收到Action之后,必须给出一个新的state,这样view才会发生变化。这种state的计算过程就叫作Reducer。
Reducer是一个纯函数,他接收Action和当前state做为参数,返回一个新的state

注意:Reducer必须是一个纯函数,也就是说函数返回的结果必须由参数state和action决定,并且不产生任何反作用也不能修改state和action对象

const reducer =(state,action)=>{
  switch(action.type){
    case ADD_TODO:
        return newstate;
    default return state
  }
}复制代码

五、Redux源码

redux一共有下边几部分构成:

* createStore
* combineReducers
* bindActionCreators
* applyMiddleware
* compose
复制代码

其中,createStore分为以下几部分

* subscribe 订阅用于刷新页面的回调事件
* dispatch 触发动做
* getState 获取当前状态下的store
* replaceReducer 替换初始化传入的reducer
* Observer 相关,不太理解如何使用,暂时略过复制代码

里面的注释就是我一步一步的分析,有点懒没有把代码拆分出来给大家看

let createStore = (reducer) => {
    let state;
    //获取状态对象
    //存放全部的监听函数
    let listeners = [];
    let getState = () => state;
    //提供一个方法供外部调用派发action
    let dispath = (action) => {
        //调用管理员reducer获得新的state
        state = reducer(state, action);
        //执行全部的监听函数
        listeners.forEach((l) => l())
    }
    //订阅状态变化事件,当状态改变发生以后执行监听函数
    let subscribe = (listener) => {
        listeners.push(listener);
    }
    dispath();
    return {
        getState,
        dispath,
        subscribe
    }
}
let combineReducers=(renducers)=>{
    //传入一个renducers管理组,返回的是一个renducer
    return function(state={},action={}){
        let newState={};
        for(var attr in renducers){
            newState[attr]=renducers[attr](state[attr],action)

        }
        return newState;
    }
}
export {createStore,combineReducers};复制代码

六、Redux使用案例

html代码

<div id="counter"></div>
  <button id="addBtn">+</button>
  <button id="minusBtn">-</button>
复制代码

js代码

function createStore(reducer) {
    var state;
    var listeners = [];
    var getState = () => state;
    var dispatch = (action) => {
        state = reducer(state, action);
        listeners.forEach(l=>l());
    }
    var subscribe = (listener) => {
        listeners.push(listener);
        return () => {
            listeners = listeners.filter((l) => l != listener)
        }
    }
    dispatch();
    return {
        getState, dispatch, subscribe
    }
}
var reducer = (state = 0, action) => {
    if (!action) return state;
    console.log(action);
    switch (action.type) {
        case 'INCREMENT':
            return state + 1;
        case 'DECREMENT':
            return state - 1;
        default:
            return state;
    }
}
var store = createStore(reducer);
store.subscribe(function () {
    document.querySelector('#counter').innerHTML = store.getState();
});

document.querySelector('#addBtn').addEventListener('click', function () {
    store.dispatch({type: 'INCREMENT'});
});
document.querySelector('#minusBtn').addEventListener('click', function () {
    store.dispatch({type: 'DECREMENT'});
});复制代码