Redux學習

来源:http://www.cnblogs.com/qingguo/archive/2016/08/05/5742700.html
-Advertisement-
Play Games

最近在這段時間瞭解了下redux,下麵簡單記錄下所得。 redux總結 首先,還是用幾句話簡單概括下redux吧,歡迎拍磚。 redux採用的函數式編程方式,基於單項數據流模式管理應用中的狀態。 一個複雜應用對應一個狀態樹,應用模塊之前共用的狀態都交由該狀態樹負責維護。 只能通過觸發action對象 ...


最近在這段時間瞭解了下redux,下麵簡單記錄下所得。

redux總結

首先,還是用幾句話簡單概括下redux吧,歡迎拍磚。

  • redux採用的函數式編程方式,基於單項數據流模式管理應用中的狀態。
  • 一個複雜應用對應一個狀態樹,應用模塊之前共用的狀態都交由該狀態樹負責維護。
  • 只能通過觸發action對象來更新狀態樹。
  • redux核心功能只提供簡單的同步方式管理應用狀態,即更新、獲取狀態。其他額外功能通過Middleware方式提供。

下麵,先通過經典應用todos簡單介紹下redux的一些基礎概念

state

state樹中存放一個應用程式內所有共用的數據,一個應用程式有且只有一個state。
todos的state結構為

{
    todos: [], // 完整的任務列表
    filter: 'SHOW_ALL' // 當前選中的任務過濾條件
}

action

action是唯一種改變state的方式,用來通知reducers修改state。
action是JavaScript plain object,描述“發生了什麼”。
預設action對象內部必須有type欄位(字元串)來表示將要執行的動作。

const ADD_TODO = 'ADD_TODO'
{
    type: ADD_TODO,
    title: '你個標題黨'
}

actionCreator就是生成action對象的函數,非常純的純函數。

function addTodo(title) {
    return {
        type: ADD_TODO,
        title
    }
}

reducer

action對象負責描述”發生了什麼“,那reducer就是執行者,按照action對象的描述,
嚴格更新state。
reducer也是一種純函數,接受action對象和state樹作為參數,生成新的state。

const reducer = (prevState, action) => nextState

這裡reducer採用純函數的意義是保證應用狀態的可預測性,只要傳入參數可知,那結果就可知。
同時nextState並不是直接修改prevState所得,而是在prevState基礎上返回的一個新數組,通過
Object.assign或者immutable.js生成。這樣的目的是方便跟蹤全局應用狀態和回退/撤銷操作,
而且可以在React組件內直接通過shouldComponentUpdate(nextProps, nextState)進行對比。
所以,千萬不要“玷污”reducer函數:

  • 修改傳入參數
  • 執行有副作用的函數,如API請求和路由跳轉
  • 調用非純函數,如Date.now()或Math.random()

最後,隨著應用的複雜,state樹也會更加龐大,reducer內部的處理邏輯也會更加複雜。很難想象一堆代
碼根據action.type的可能值進行判斷處理。
我們可以通過分解、細化reducers來拆分數據處理邏輯,最後通過redux提供的combineReducers()
API來生成唯一的rootReducer。

const todoApp = combineReducers({
  visibilityFilter,
  todos
})

store

store就是將action和reducer聯繫在一起的對象。

const = createStore(reducer, initState)

store對象有三種方法,通過這三種方法來維持應用的state。

  • 提供getState()方法獲取應用的state
  • 提供dispatch(action)方法通知reducer根據action對象更新state
  • 提供subscribe(listener)註冊監聽器,監聽state的更新,然後調用listener函數
  • 通過subscribe(listener)返回的函數註銷監聽器

至此,redux的核心方面已經說完。你可能發現這個redux似乎和觀察者模式差不多呢。其實,它就是一個觀察者模式。
我們可以通過babel-node執行我們的todos查看redux應用的調用過程。

ps: balel-node是node中安裝babel插件轉換ES6代碼,此時node v6.3.1還不支持export & import用法
上面redux調用流程圖:

redux只是一種應用狀態管理器,我們需要通過react-redux結合React一起使用才能開發出完整的應用。

react-redux

react-redux是redux官方提供的一種綁定react的實現方案。主要提供了兩個api:

  • <Provider store>包裹React頂層組件,並且為子組件傳遞Redux store props
  • connect([mapStateToProps], [mapDispatchToProps])

connect方法主要有可選參數,具體可參考官網API文檔,不過平常主要使用這兩個

  • mapStateToProps(state) 每次state樹更新時,都會被connect調用,返回需要傳遞給子組件的state對象,並被組合到react組件的props中。
  • mapDispatchToProps(dispatch): mapDispatchToProps負責返回一個 dispatchProps。dispatchProps 是actionCreator的key和dispatch(action)的組合。

{ addItem: (text) => dispatch(action1), removeItem: (id) => dispatch(action2) }
react組件內部通過this.props.addItem('hello')調用。
如果有多個action情況,可以通過如下方式進行綁定:
bindActionCreators(actionCreator, store.dispatch)
bindActionCreators 的作用就是將 actionCreator 和 dispatch 組合起來生成 mapDispatchToProps 需要生成的內容。

Middleware(中間件)

在介紹接下來的內容之前,插個已經被問爛的問題:什麼是js閉包和函數柯里化。此處只是簡單的舉個例子說明一下

let test = (a, b) => a + b
let curryTest = a => b => test(a, b)

好,接下來繼續扯我們的,什麼是Middleware
此處,Redux Middleware的設計思路來自於Express,即通過Middleware實現對store.dispatch的封裝,擴展
該函數原有的功能,典型的是實現state日誌記錄的功能。

// 手動記錄logger功能代碼
console.log('dispatching', action)
store.dispatch(action)
console.log('next state', store.getState())

而redux通過Middleware建立一個store.dispatch的鏈條,每層middleware都會接受前一個middleware返回
的next, 然後在進行封裝,返回給後一個middleware調用的next,直到最後一個middleware返回
原始的store.dispatch處理action對象。
例如官網的logger middleware代碼:

const logger = store => next => action => {
  console.log('dispatching', action)
  let result = next(action)
  console.log('next state', store.getState())
  return result
}

applyMiddleware(...middlewares)源碼:

export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, initialState, enhancer) => {
    var store = createStore(reducer, initialState, enhancer)
    var dispatch = store.dispatch
    var chain = []

    var middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

compose(..funcs)源碼

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  } else {
    const last = funcs[funcs.length - 1]
    const rest = funcs.slice(0, -1)
    return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))
  }
}

通過源碼我們能發現,applyMiddleware接受的Middlewares數組除了最後一個middleware接受原始的store.dispatch(Array.prototype.reduceRight),其餘middleware都會接受前一個middleware封裝後的next,所以此時的redux流程圖就是下麵這樣:

介紹完redux的middleware,那redux的非同步流程模式也就出來了。官網是通過redux-thunk Middleware實現的,我們看下thunkMiddleware的源碼:

function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}

這樣store.dispatch就可以接受函數,也就可以將其和網路請求狀態動態綁定在一起了。
具體源碼可參考官網async示例源碼。

本文參考鏈接:

  1. http://redux.js.org/index.html
  2. http://cn.redux.js.org/
  3. http://www.jianshu.com/p/3334467e4b32

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • jQuery的toggle()方法應該是在滑鼠點擊後才會觸發,現在的問題是在ready載入後就自動觸發了,怎麼回事呢? 答案是jQuery的版本問題,在1.9以後的版本toggle()就存在這個問題,用之前的版本就正常了。​ 如果你非常喜歡這個功能,有2個辦法,一個辦法是jquery官網提供的一個版 ...
  • 先上一張簡約的界面的效果圖 這裡是style裡面的內容 再來body裡面的內容,這裡用到的是失焦 onblur 和聚焦 onfocus <body> <center> <div> <form> <h3>用戶註冊</h3> <hr> <p>用戶名:<input type="text" id="name ...
  • 序號 方法 舉例 是否改變當前數組 1 instanceof 判斷變數是否是數組對象 否 2 join 將數組的元素組起一個字元串 join(separator) //將數組的元素組起一個字元串,以separator為分隔符,省略的話則用預設用逗號為分隔符 arr1 = [1,2,3,4,5]; r ...
  • 一、引言 JavaScript的內容分為三個部分,這三個部分分別是ECMAScript、DOM、BOM三個部分組成。所謂ECMAScript就是JavaScript和核心基礎語法,DOM是文檔對象模型,最後剩下的BOM則是瀏覽器對象模型。這三個部分相輔相成組成了現在的JavaScript。 二、導入 ...
  • 在做WEB開發的時候我們經常會遇到分頁的處理,如果在PC上顯示網頁的話,使用傳統的分頁是可以接受的。那麼,當我們為手機或其他移動端設計界面的話,使用分頁未免有些笨拙和難以使用,這時候我們可以使用在單頁載入所有列表項。當屏幕滑動到最低端的時候,會出現“點擊載入更多”的按鈕,當我們點擊此按鈕的時候,會加 ...
  • 名字的聲明就是讓我的解釋器知道有這個名字 名字沒有任何數據與之對應 函數聲明包含兩部分 首先告訴解釋器函數的名字 告訴解釋器 這個名字對應的函數體是什麼 函數聲明與函數表達式有區別,函數聲明是單獨寫在一個結構中,不存在任何語句,邏輯判斷等結構中 ``` 函數聲明: function(){} func ...
  • 今天沒有說什麼內容,只是對HTML5的細節補充,如HTML結構的可以省略到最大的地步 沒有了基本的結構標簽了,瀏覽器會自動幫我們生成。 還有標簽的屬性的雙引號也可以省略; HTML5讓我體驗到它在最大化的簡化標簽,使代碼量最小化。 還有調試工具的使用,調試工具讓我們更快的更準確的查到各方面的信息, ...
  • <script> function lol(type) { if(typeof type == "undefined") { alert("undefined"); } else if(typeof type == "object") { if(new String(type) == "null") ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...