Redux的createStore實現

做者:米卡node

Redux的createStore實現

  使用過react的同窗應該對Redux這個東西有所瞭解。他是一種全局狀態管理的思想(對, 這裏我以爲它是一種思想, 由於對於React來講, 其實Redux內部並無什麼須要與React兼容的東西, react-redux 庫裏纔有), 它信奉的是:react

  • 惟一數據倉庫
  • 只能讀取
  • 數據改變只能經過純函數進行

  這其實對咱們是一種約束, 畢竟咱們就算引入了Redux, 也能使用this.props去進行父子組件數據傳輸, 可是當你須要非父子組件的通訊的時候, 裏面的數據流動會很是難以捉摸, 因此咱們使用Redux。redux

在React中集成Redux時, 在程序的入口處,咱們能夠看到這樣的一段代碼數組

// 這裏的todoApp是一個Reducer函數,接受的是state和actions
const store = createStore(todoApp)
複製代碼

  在咱們的react使用單一倉庫的時候,能看到一下的一些相似的代碼,從中咱們能看到,咱們本組件的state是經過this.state = store.getState()所建立的, 那麼咱們的store是一個對象,裏面有一個getState函數可以返回內部的state,同時這個state是須要持久保存的,因此咱們大概能有一些思路。markdown

import React, { Component } from 'react'
import store from '../../store'
import { getIPData } from '../../store/actionCreators'
 class Page extends Component { // 個人初始化的一個組件,已經可以使用Redux了 constructor(props) { super(props); this.state = store.getState() store.subscribe(this.storeChange.bind(this)); }  componentWillMount() { // 獲取IP數據,這裏是做爲一個dispatch的例子 // 值得注意的是getIPData()返回的是一個帶type字段的一個對象。 const action = getIPData(); store.dispatch(action); }  render() { return ( <div className="page"> </div> ) }  storeChange() { this.setState(store.getState()) } } export default Page 複製代碼

  接下來我將本身寫的createStore函數貼出來, 而後講解。這個函數實現了大部分功能,可是對於中間件的處理這裏並無可以實現,後面我應該會對其有一些補充。閉包

函數

export default function createStore(reducer){ let state = null; const listeners = []; const getState = () => state
<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">const</span> dispatch = <span class="hljs-function" style="line-height: 26px;">(<span class="hljs-params" style="line-height: 26px;">action</span>) =&gt;</span> {
    state = reducer(state, action)
    listeners.forEach(<span class="hljs-function" style="line-height: 26px;"><span class="hljs-params" style="line-height: 26px;">listener</span> =&gt;</span> listener())
}

<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">const</span> subscribe = <span class="hljs-function" style="line-height: 26px;">(<span class="hljs-params" style="line-height: 26px;">listener</span>) =&gt;</span> listeners.push(listener)

<span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 這裏初始化dispatch的緣由是在這以前,state是爲null的</span>
<span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//因此我須要傳一個不存在的action去reducer裏面,拿到最默認的那個defaultState</span>
<span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//這個defaultState寫在reducer的那個文件裏面</span>
dispatch({});
<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span> {
    dispatch,
    subscribe,
    getState,
}
複製代碼
複製代碼<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">const</span> dispatch = <span class="hljs-function" style="line-height: 26px;">(<span class="hljs-params" style="line-height: 26px;">action</span>) =&gt;</span> { state = reducer(state, action) listeners.forEach(<span class="hljs-function" style="line-height: 26px;"><span class="hljs-params" style="line-height: 26px;">listener</span> =&gt;</span> listener()) } <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">const</span> subscribe = <span class="hljs-function" style="line-height: 26px;">(<span class="hljs-params" style="line-height: 26px;">listener</span>) =&gt;</span> listeners.push(listener) <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 這裏初始化dispatch的緣由是在這以前,state是爲null的</span> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//因此我須要傳一個不存在的action去reducer裏面,拿到最默認的那個defaultState</span> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//這個defaultState寫在reducer的那個文件裏面</span> dispatch({}); <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span> { dispatch, subscribe, getState, } 複製代碼}

  因此剛纔的分析, 咱們須要建立一個函數對象createStoreoop

  一、createStore裏面用閉包的方法儲存了一個state,咱們程序用到的倉庫就是這個、還儲存有一個函數數組listeners,用於儲存用戶定義的函數(通常是用更新後的倉庫重置this.state),由於我其實有多個頁面都註冊了一個訂閱函數, 因此使用函數數組, 當須要分發時取出來取出來調用便可。this

  二、createStore須要定義一個方法getState可以拿到state,這樣就可以在React中使用this.state = store.getState()來初始化state並進行讀取了spa

  三、createStore還須要定義一個方法dispatch, 由於redux不能直接修改state的值, 因此必須經過dispatch函數,傳入action, 而後帶着state直接傳入reducer裏, reducer會傳回修改後的state

  四、createStore再須要定義一個方法subscribe, 這是用來監聽修改的函數, 在使用時, 綁定一個函數, 這個函數裏會在外界得到state。因此這個函數應該接收一個函數, 而後push入一個隊列裏, 但是應該實時監聽的, 爲什麼要置入隊列呢?這裏個人理解是, 在一開始就將"外界從新得到state"這個函數置入隊列, 相似Promise我承諾會使用這個函數。因此這個函數的使用應該放置在dispatch裏面, 它傳回一個state後, 作的事情是將全部隊列中的"外界從新得到state"函數所有拿出來執行一遍。

  因此這個createStore函數的效果很明顯了,getState用於獲取當前state, subscribe用於給外界設置監聽並將監聽函數儲存在createStore函數的屬性中, 每次用戶經過dispatchaction來修改state的時候, 將裏面全部的監聽函數拿出來執行一遍。而dispatch則是用來執行state修改的, 畢竟這個函數不容許使用setState這類的函數。

  這樣, 咱們就簡單瞭解並分析了Redux的基本原理並對其進行了重寫, 就像我提到的, Redux實際上是一種約束的思想而出現, 這意味着在node中, 咱們一樣也能使用Redux(雖然我以爲可能沒有必要)

本文使用 mdnice 排版

相關文章
相關標籤/搜索