摘要:是一個程序架構,源于提出的一種架構,然而,它不僅可以應用于,還可以應用于其他任何框架中。有以下職責維持應用的提供方法獲取提供方法更新通過注冊監聽器通過返回的函數注銷監聽器。同時,的返回值實際上是一個函數可以解除監聽。
Redux是一個程序架構,源于Flux(Facebook提出的一種架構),然而,它不僅可以應用于React,還可以應用于其他任何框架中。值得一提的是,Redux的源代碼很少,但是他的邏輯拆分和函數式編程的設計思想是非常值得學習的。
1. 解決的問題當一個JavaScript單頁應用變得越來越復雜時,我們要處理的數據(model)也變得越來越龐大,隨之而來的是每個數據的狀態(state)會變得難以維護。當一個model改變時,我們可能要手動處理由此引發的其他model的變化,更糟糕的是,其他model變化可能又會引起另一些model的變化,這樣產生連鎖反應。最后我們很容易就會不記得model在什么時候以及如何發生改變。這正是Redux可以解決的最大痛點之一—以統一的方式管理數據狀態。
統一的數據狀態管理體現為以下2個方面:
組件間的數據通信
UI和數據處理邏輯分離
2.三大原則
單一數據源
整個應用的 state 被儲存在一棵 object tree 中,并且這個 object tree 只存在于唯一一個 store 中。
State是只讀的
唯一改變 state 的方法就是觸發 action,action 是一個用于描述已發生事件的普通對象。
Reducer必須是純函數
3.基本概念
Action
Action 是把數據從應用傳到 store 的有效載荷。它是 store 數據的唯一來源。直白的說,action就是一種消息類型,他告訴Redux是時候該做什么了,并帶著相應的數據傳到Redux內部(即接下來介紹的Reducer)。
Action就是一個簡單的對象,其中必須要有一個type屬性,用來標志動作類型(reducer以此判斷要執行的邏輯),其他屬性用戶可以自定義,但要盡量簡單。如:
{type: SET_ALL,index: 5}
Action Creator
Action Creator是一個用來自動生成Action的函數,這也是Redux函數式編程的一種體現。通常,我們會按照業務邏輯或組件把相關的Action Creator放在一個文件中,形式如下:
export const SHOW_SLIDER = "SHOW_SLIDER"; export const RIGHT_SLIDER = "RIGHT_SLIDER"; export const showSliderAction = (index) => { return { type: SHOW_SLIDER, index }; } export const rightSliderAction = (length) => { return { type: RIGHT_SLIDER, length }; }
其中showSliderAction和rightSliderAction就是Action Creator。
由于Action Creator的形式大體相同,我們還可以創建一個用來生成Action Creator的函數以進一步簡化。
export const makeCreateAction = (type, ...keys) => { return (...data) => { let action = {type}; keys.forEach((v,i) => action[v] = data[i]); return action; } } export const showSliderAction = makeCreateAction(SHOW_SLIDER, index); export const rightSliderAction = makeCreateAction(RIGHT_SLIDER, length);
Reducer
Reducer 指定了應用狀態的變化如何響應 actions 并發送到 store 的,action只是告訴Redux該干什么了,并沒有告訴他怎么干,而reducer就是根據action處理state如何改變的邏輯。
Reducer必須是一個純函數(原因稍后解釋),他根據action處理state的更新,如果沒有更新或遇到未知action,則返回舊state;否則返回一個新state對象。注意:不能修改舊state,必須先拷貝一份state,再進行修改,也可以使用Object.assign函數生成新的state。另外,state參數需先進行初始化。實例代碼如下:
//初始狀態 let initialState = {hiddenClass: "g-hidden",currentIndex:0}; let sliderReducer = function (state = initialState, action) { switch(action.type){ case sliderAction.SHOW_SLIDER: return {hiddenClass: "",currentIndex:action.index}; case sliderAction.RIGHT_SLIDER: if(state.currentIndex == action.length-1){ return Object.assign({}, state, {currentIndex:0}); }else{ return Object.assign({}, state, {currentIndex:Number.parseInt(state.currentIndex)+1}); } default: return state; } } export default sliderReducer;
使用純函數的原因:
首先,純函數的特點是: ?函數的返回結果只依賴于它的參數。 ?函數執行過程里面沒有副作用。(不會對外界產生影響)
如果不使用純函數,即直接更改state值會怎么樣呢?
… … case sliderAction.RIGHT_SLIDER: if(state.currentIndex == action.length-1){ state.currentIndex = 0; return state; } … …
之后會發現,無論state如何變化,UI都不會更新。以下是Redux的部分源碼:
通過查看Redux源碼得知,新舊state的比較只是對引用地址的比較,如果reducer只是返回舊state(即previousStateForKey)的更新,新state(nextStateForKey)實際上和舊state引用的都是同一塊內存地址,所以無論如何更改,新舊state始終保持相同。這就是為什么reducer必須是純函數的原因。
Reducer拆分與合并:
Reducer 函數負責生成 State。由于整個應用只有一個 State 對象,包含所有數據,對于大型應用來說,這個 State 必然十分龐大,導致 Reducer 函數也十分龐大。所以需要先對reducer進行拆分,拆分的原則可以按業務邏輯進行劃分,如果是react的話,可以直接和react的組件相對應進行劃分。
劃分好之后,可以用Redux提供的combineReducers方法進行合并,十分方便。
import { combineReducers } from "redux"; import photomainReducer from "./photomainReducer"; import sortReducer from "./sortReducer"; import sliderReducer from "./photoSliderReducer"; export default combineReducers({ photomainReducer, sortReducer, sliderReducer });
Store
Store 是把Action、Reducer聯系到一起的對象。Store 有以下職責:
1.維持應用的 state; 2.提供 getState() 方法獲取 state; 3.提供 dispatch(action) 方法更新 state; 4.通過 subscribe(listener) 注冊監聽器; 5.通過 subscribe(listener) 返回的函數注銷監聽器。
(1) 創建store
Redux應用應該只有一個store,他提供了創建store的API—createStore(reducer, initState)。第一個參數為一個reducer,可以接受通過combineReducers合并后的reducer,第二個是可選參數,意思是可以設置應用的初始state。
const store = createStore( indexPhotomainReducer, ); export default store;
(2)State
應用的state也應該只有一個,里面包含了所有的應用數據。當需要獲取state的時候,需要使用store.getState()方法。
(3)store.dispatch(action)
UI更新state 的唯一途徑,通過dispatch方法發起action,喚起對應的reducer更新state。
(4)store. subscribe(listener)
通過此方法可以設置監聽函數,一旦state發生變化,就會立即調用監聽函數(listener)。同時,subscribe的返回值(實際上是一個unsubscribe函數)可以解除監聽。如:
// 每次 state 更新時,打印日志 // 注意 subscribe() 返回一個函數用來注銷監聽器 const unsubscribe = store.subscribe(() => console.log(store.getState()) ) // 停止監聽 state 更新 unsubscribe();4.數據流
(1)首先,用戶發出 Action(如click事件)。
store.dispatch(SHOW_SLIDER)
(2) Store 自動調用 Reducer,并且傳入兩個參數:當前 State 和收到的 Action。 Reducer根據Action的type調用相應的分支, 返回新的 State 。
let initialState = {hiddenClass: "g-hidden",currentIndex:0}; let sliderReducer = function (state = initialState, action) { switch(action.type){ case sliderAction.SHOW_SLIDER: return {hiddenClass: "",currentIndex:action.index}; default: return state; } }
(3) State 一旦有變化,Store 就會調用監聽函數。
store.subscribe(listener);
(4) listener可以通過store.getState()得到當前狀態。如果使用的是 React,這時可以觸發重新渲染 View。
function listerner() { let newState = store.getState(); component.setState(newState); }
以上為Redux的數據流動過程。
本篇到此告一段落,下一篇介紹Redux的異步實現。
參考Redux 中文文檔
Redux 入門教程-阮一峰
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94840.html
摘要:異步實現設計需要增加三種通知異步請求發起的異步請求成功的異步請求失敗的示例代碼如下返回參數完全可以自定義。這種分別在請求開始前,請求成功后,請求失敗后發送。表示數據的有效性,他的作用是在異步請求發送失敗后,告訴當前的數據是過時的數據。 說明:對Redux不了解的同學可先看看這篇文章Redux技術架構簡介(一) 前言 這里說的Redux異步實現,是專指Redux中的異步Action實現,...
摘要:應用這說明并不是單指設計給用的,它是獨立的一個函數庫,可通用于各種應用。在數據流的最后,要觸發最上層組件的,然后進行整體的重新渲染工作。單純在的對象上是沒有辦法使用,要靠額外的函數庫才能這樣作,這是一定要使用類似像這種函數庫的主要原因。 Redux的官網中用一句話來說明Redux是什么: Redux是針對JavaScript應用的可預測狀態容器 這句話雖然簡短,其實是有幾個涵義的: ...
摘要:展示組件與容器組件的綁定庫的基本開發思想是展示組件與容器組件相分離。技術上講,容器組件就是使用從樹中讀取部分數據,并通過來把這些數據提供給要渲染的組件。 說明:閱讀本篇文章需要對Redux有一定的了解,對Redux不了解的同學可先看看這篇文章Redux技術架構簡介(一) 1. React中引入react-redux 為了讓Redux和React更好的配合,Facebook專門開發了一個...
摘要:另外,內置的函數在經過一系列校驗后,觸發,之后被更改,之后依次調用監聽,完成整個狀態樹的更新。總而言之,遵守這套規范并不是強制性的,但是項目一旦稍微復雜一些,這樣做的好處就可以充分彰顯出來。 這一篇是接上一篇react進階漫談的第二篇,這一篇主要分析redux的思想和應用,同樣參考了網絡上的大量資料,但代碼同樣都是自己嘗試實踐所得,在這里分享出來,僅供一起學習(上一篇地址:個人博客/s...
摘要:另外,內置的函數在經過一系列校驗后,觸發,之后被更改,之后依次調用監聽,完成整個狀態樹的更新。總而言之,遵守這套規范并不是強制性的,但是項目一旦稍微復雜一些,這樣做的好處就可以充分彰顯出來。 這一篇是接上一篇react進階漫談的第二篇,這一篇主要分析redux的思想和應用,同樣參考了網絡上的大量資料,但代碼同樣都是自己嘗試實踐所得,在這里分享出來,僅供一起學習(上一篇地址:個人博客/s...
閱讀 1804·2023-04-26 02:14
閱讀 3727·2021-11-23 09:51
閱讀 1385·2021-10-13 09:39
閱讀 3971·2021-09-24 10:36
閱讀 3012·2021-09-22 15:55
閱讀 3518·2019-08-30 12:57
閱讀 2039·2019-08-29 15:30
閱讀 1986·2019-08-29 13:19