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'});
});複製代碼
相關文章
相關標籤/搜索