標籤:

React + HOC + Redux 極簡指南

為何要引入Redux?

我們知道React的組件基本上都是純函數、當組件化完成之後不可避免的上層要思考的一個問題就是:

一個應用內眾多的組件應該如何調度?

面對這個問題,各路大神都有想過解決方案,引入Redux便是目前行業內最常見的做法

Redux的基本思想:Web應用是一個狀態機、視圖與狀態是一一對應的,所有的狀態、保存在一個對象裡面。所有控制邏輯都通過無副作用的函數創建新狀態

可以看出合react一脈相承、一股濃厚的functional味道(寫過scala的人對此應該不會陌生)

總有人說React概念多,但從程序員的角度來看這些概念都真的很簡單

只需要幾行偽代碼就可以說清楚:

declare var hoc, render, reducer, middleware, View, State, Action;nn//React組件可以視為一個狀態到視圖的映射nView = render(State)n//React高階組件(hoc):可以看做組件(上狀態到視圖映射)的裝飾器nrender = hoc(render)n//Redux reducer可以看做當前狀態 + 當前動作的求解、求解後返回新的狀態nState = reducer(State, Action)n//Redux middleware可以看做對Action添加的前置、後置處理(如列印日誌、非同步處理)nAction = middleware(dispatch)(event)nn//所以最終react + redux無非是一個Action出發的循環:nnwhile (event) {//外部變化觸發event(用戶輸入、網路變化、後台推送...)n Action = middleware(dispatch)(event)n State = reducer(State, Action) //Action導致內存狀態State的變化n View = hoc(render)(State) //內存狀態State的變化觸發重新渲染n}nn//如果再考慮到react-reduxnwhile(event){n Action = middleware(dispatch)(Action)n State = reducer(State, Action)n mapStateToProps = state => staten mapDispatchToProps = dispatch => bindActionCreators(actionCreators,dispatch)n View = connect(mapStateToProps,mapDispatchToProps)(hoc(render))(State)n}n

思想理解了接下來就是實際擼代碼咯:

如何編寫HOC

真的就是一個函數而已,真的是簡單到不能在簡單了~

for example:

const yell = (PassedComponent) =>n ({ children, ...props }) =>n <PassedComponent {...props}>n {children.toUpperCase()}!n </PassedComponent>nnconst Title = (props) => <h1>{props.children}</h1>nconst AngryTitle = yell(Title)nn<AngryTitle>Whatever</AngryTitle>n

更多內容可以看 @冉余 的專欄 :面向初學者的高階組件教程 - 知乎專欄

如何編寫reducer

reducer是用來改變狀態的、而改變狀態無非三種操作(增刪改)、不過reducer強調的是純函數、操作方法比較考究,只要理解es6的展開運算符 和Javascript的Array API也無任何難點:

var reducer = function (state = {n items: [],n}, action: any) {n switch (action.type) {nn case ADD:n return {n ...state,n items: state.items.concat(action.payload),n };n case DELETE: {n return {n ...state,n items: state.items.filter(function (item) {n return item.id !== action.idn }),n }n }n case EDIT: {n var items = state.items.map((item) => {n if (item.id === action.id) {n return {n ...item,n key: action.payload[key]n }n } else {n return itemn }n });n return {n ...state,n items: itemsn }n }n }n}n

如何編寫Middleware

先說為何引入middleware

action -> dispatcher -> reducers

如果我們接到需求讓所有的action列印日誌 怎麼辦? 改每一個action ? 太low ! 給action一個繼承體系,太死!聯想到後端開發:最簡單的途徑就是middleware :

action -> dispatcher -> middleware1 -> middleware2 -> .... -> reducers

寫個例子:

import { applyMiddleware, compose, createStore } from redux;nimport reducer from ./reducer;nimport thunk from redux-thunk;nnvar finalCreateStore:any = compose(n applyMiddleware(thunk, function middleware1({ dispatch, getState }) {n return next => action => {n console.log(middleware1 start)n next(action);n console.log(middleware1 end)n }n },n function middleware2({ dispatch, getState }) {n return next => action => {n console.log(middleware2 start)n next(action);n console.log(middleware2 end)n }n },)n)(createStore);n

除了redux-thunk以外我們自己又寫了兩個組件:

最終action時的列印結果:

middleware1 start

middleware2 start

middleware2 end

middleware1 end

可以看出 middleware的執行順序

像剝洋蔥一樣 按數據順序逐層向里 next執行完後再逐層向外返回

想更多的了解middleware的用法推薦閱讀 @胡滿川 的專欄: redux middleware 詳解 - 知乎專欄


推薦閱讀:

TAG:React | Redux |