摘要:沿著管道有兩組偵聽器中間件和訂閱。中間件是可以偵聽傳入的動作的函數(shù),支持諸如,或偵聽器之類的工具。將視為一個帶有更新前更新后鉤子的全局對象,以及能夠以簡單的方式合成新狀態(tài)。應(yīng)將兩者視為一體,并且不再需要文件導(dǎo)出類型的字符串。
難道現(xiàn)在狀態(tài)管理不是一個可以解決的問題嗎?直觀地說,開發(fā)人員似乎知道一個隱藏的事實:狀態(tài)管理的使用似乎比需要的更困難。在本文中,我們將探討一些你可能一直在問自己的問題:
你是否需要一個用于狀態(tài)管理的庫?
Redux 的受歡迎程度是否值得我們?nèi)ナ褂茫?為什么或者為什么不值得?
我們能否制定更好狀態(tài)管理解決方案嗎?如果能,要怎么做?
想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你!
狀態(tài)管理需要一個庫嗎作為前端開發(fā)人員,不僅僅是布局,開發(fā)的真正藝術(shù)之一是知道如何管理存儲狀態(tài)。簡而言之:狀態(tài)管理是復(fù)雜的,但又并非那么復(fù)雜。
讓我們看看使用React等基于組件的視圖框架/庫時的選項:
1. Component State (組件狀態(tài))存在于單個組件內(nèi)部的狀態(tài)。在React中,通過setState方法更新state。
2. Relative State (關(guān)聯(lián)狀態(tài))從父級傳遞給子級的狀態(tài)。在React中,將 props 作為屬性傳遞給子組件。
3. Provided State (供給狀態(tài))狀態(tài)保存在根 provider (提供者) 組件中,并由 consumer (消費(fèi)者) 在組件樹的某個地方訪問,而不考慮組件之間的層級關(guān)系。在 React 中,通過 context API 可以實現(xiàn)。
大多數(shù)的狀態(tài)都是存在于視圖中的,因為它是用來反映用戶界面的。那么,對于反映底層數(shù)據(jù)和邏輯的其它狀態(tài),又屬于誰呢?
將所有內(nèi)容都放在視圖中可能會導(dǎo)致關(guān)注點(diǎn)的分離:它將與javascript視圖庫聯(lián)系在一起,使代碼更難測試,而且可能最大的麻煩是:必須不斷地思考和調(diào)整存儲狀態(tài)的位置。
狀態(tài)管理由于設(shè)計變更而變得復(fù)雜,而且通常很難判斷哪些組件需要哪些狀態(tài)。最直接的選擇是從根組件提供所有狀態(tài),如果真要這么做的話,那么選用下一種方式會更好。
4. External State (外部狀態(tài))狀態(tài)可以移出視圖庫。然后,庫可以使用提供者/消費(fèi)者模式連接以保持同步。
也許最流行的狀態(tài)管理庫是Redux。在過去的兩年里,它變得越來越受歡迎。那么為什么這么喜歡一個簡單的庫呢?
Redux 更具性能?答案是否定的。事實上,為了每一個必須處理的新動作(action),都會稍微慢一些。
Redux是否更簡單?當(dāng)然不是。
簡單應(yīng)當(dāng)是純javascript:比如 TJ Holowaychuk 在twitter上說
那么為什么不是每個人都使用 global.state={}?
為什么使用 Redux在表層之下,Redux 與 TJ 的根對象{}完全相同——只是包裝在了一系列實用工具的管道(pipeline)中。
在 Redux 中,不能直接修改狀態(tài)。只有一種方法:派發(fā)(Dispatch)一個動作(Action)到管道中,管道會自動根據(jù)動作去更新狀態(tài)。
沿著管道有兩組偵聽器:中間件(middleware)和訂閱(subscriptions)。 中間件是可以偵聽傳入的動作的函數(shù),支持諸如“l(fā)ogger”,“devtools”或“syncWithServer”偵聽器之類的工具。 訂閱是用于廣播這些狀態(tài)更改的函數(shù)。
最后,合成器(Reducer)函數(shù)負(fù)責(zé)把狀態(tài)變更拆分成更小、更模塊化、更容易管理的代碼塊。
和使用一個全局對象相比,Redux 確實簡化了開發(fā)過程。
將 Redux 視為一個帶有更新前/更新后鉤子的全局對象,以及能夠以簡單的方式合成新狀態(tài)。
Redux 是不是太復(fù)雜了?是的。有幾個不可否認(rèn)的跡象表明 API 需要改進(jìn),這些可以用下面的方程來總結(jié)
time_saved來表示你開發(fā)自己的解決方案所花費(fèi)的時間,time_invested相當(dāng)于閱讀文檔,學(xué)習(xí)教程和研究不熟悉的概念所花費(fèi)的時間。
Redux 是一個擁有陡峭學(xué)習(xí)曲線的小型庫。雖然有不少開發(fā)者能夠克服深入學(xué)習(xí)函數(shù)式編程的困難并從 Redux 獲益良多,但是也有很多開發(fā)者望而卻步,寧愿重新使用 jQuery。
使用jQuery你不需要理解“monad”是什么,你也不需要為了使用Redux去理解函數(shù)組合。
使用 jQuery 你不需要理解“comonad”是什么,你也不需要為了使用 Redux 去理解函數(shù)組合。
任何框架或者庫的目的都應(yīng)該是把復(fù)雜的事物抽象得更加簡單。
重新設(shè)計Redux我認(rèn)為Redux值得重寫,至少有以下 6 個方面可以改進(jìn)得更友好。
1.初始化讓我們來看看一個基本的 Redux 初始化過程,如下圖左邊所示:
許多開發(fā)人員在第一步后就在這里暫停,茫然地盯著深淵。 什么是 thunk?compose?一個函數(shù)能做到這些嗎?
如果 Redux 是基于配置而不是函數(shù)組合的話,那么像右邊那樣的初始化過程明顯看起來更加合理。
2. 簡化 reducersRedux 中的 reducers 可以通過一個轉(zhuǎn)換,讓我們遠(yuǎn)離已經(jīng)習(xí)慣但不必要且冗長的 switch 語句。
假設(shè)reducer與action類型匹配,那么我們可以對參數(shù)進(jìn)行反轉(zhuǎn),這樣每個reducer都是一個接受state 和action的純函數(shù)。 也許更簡單,我們可以標(biāo)準(zhǔn)化action并僅傳入state和有效負(fù)載(payload)。
3.使用 Async/Await 代替 Thunksthunk 通常用于在 Redux 中創(chuàng)建異步 action。 在許多方面,thunk 的工作方式看起來更像是一個聰明的黑客,而不是官方推薦的解決方案。 我們一步一步來看:
你派發(fā)一個action(dispatch an action),它實際上是一個函數(shù)而不是預(yù)期的對象。
thunk 中間件檢查每個動作,看看它是否是一個函數(shù)。
如果是,中間件調(diào)用該函數(shù),并傳入一些 store 的方法:dispatch 和 getState。
怎么會這樣?一個簡單的 action 到底是作為一個動態(tài)類型的對象、一個函數(shù),還是一個 Promise?這難道不是一種拙劣的實踐嗎?
如上圖右邊所示,難道我們就不能只使用 async/await ?
4. 兩種 action仔細(xì)想想,其實有兩種 action
1.reducer action: 觸發(fā) reducer 并改變狀態(tài)。
2.effect action:觸發(fā)異步 action,這可能會調(diào)用reducer操作,但異步函數(shù)不會直接更改任何狀態(tài)。
將這兩種類型的 action 區(qū)分開來,將比上面的thunk用法更有幫助,也更容易理解。
5. 不再有 action 類型(action.type)變量為什么我們的標(biāo)準(zhǔn)實踐要把 action creator 和 reducer 區(qū)分開來呢?能否只用其中一個呢?改變其中一個又是否會影響到另一個?
action creator 和 reducer 是同一枚硬幣的兩面。
const ACTION_ONE = "ACTION_ONE"是分離 action creators 和 reducers 的一個冗余產(chǎn)物。應(yīng)將兩者視為一體,并且不再需要文件導(dǎo)出類型的字符串。
6.reducers 即 action creators按照使用方式,把 Redux 中所涉及的概念進(jìn)行合并分組,那么我們可以得出下面這個更簡單的模式。
可以從 reducer 中自動確定 action creator。 畢竟,在這種情況下,reducer 可以成為action creator。
使用一個基本的命名約定,下面是可預(yù)測的:
如果 reducer 命名為 increment,那么 type 就是 increment。更好的做法是加上命名空間 “count/increment”。
每個 action 都通過 payload 鍵來傳遞數(shù)據(jù)。
現(xiàn)在,從 count.increment 中,我們可以以一個 reducer 生成 action creator。
好消息:我們可以有一個更好的 Redux以上這些痛點(diǎn)就是我們創(chuàng)建 Rematch 的原因。
Rematch 對 Redux 進(jìn)行了封裝,提供更簡單的 API,但又不失任何可配置性的特點(diǎn)
請參見下面的一個完整的 Rematch 示例:
在過去的幾個月里,我一直在實際業(yè)務(wù)中使用 Rematch。作為證明,我會說:狀態(tài)管理從未變得如此簡單、高效。
Redux 與 Rematch 的對比Redux 是一個出色的狀態(tài)管理工具,有鍵全的中間件生態(tài)與出色的開發(fā)工具。
Rematch 在 Redux 的基礎(chǔ)上構(gòu)建并減少了樣板代碼和執(zhí)行了一些最佳實踐。
說得清楚點(diǎn),Rematch 移除了 Redux 所需要的這些東西:
聲明 action 類型
action 創(chuàng)建函數(shù)
thunks
store 配置
mapDispatchToProps
sagas
讓 Redux 與Rematch 作對比有助于讓理解更加清晰。
Rematch1.model
import { init } from "@rematch/core" const count = { state: 0, reducers: { upBy: (state, payload) => state + payload } } init({ model: { count } })
2.View
import { connect } from "react-redux" // Component const mapStateToProps = (state) => ({ count: state.count }) const mapDispatchToProps = (dispatch) => ({ countUpBy: dispatch.count.upBy }) connect(mapStateToProps, mapDispatchToProps)(Component)Redux (最佳實踐)
1.store
import { createStore, combineReducers } from "redux" // devtools, reducers, middleware, etc. export default createStore(reducers, initialState, enhancers)
2.Action Type
export const COUNT_UP_BY = "COUNT_UP_BY"
3.Action Creator
import { COUNT_UP_BY } from "../types/counter" export const countUpBy = (value) => ({ type: COUNT_UP_BY, payload: value, })
4.Reducer
import { COUNT_UP_BY } from "../types/counter" const initialState = 0 export default (state = initialState, action) => { switch (action.type) { case COUNT_UP_BY: return state + action.payload default: return state } }
5.view
import { countUpBy } from "../actions/count" import { connect } from "react-redux" // Component const mapStateToProps = (state) => ({ count: state.count, }) connect(mapStateToProps, { countUpBy })(Component)Rudex 與 Rematch 的分?jǐn)?shù)板
Redux 并沒有被拋棄,而且也不應(yīng)該被拋棄。
只是,我們應(yīng)該以更低的學(xué)習(xí)成本,更少的樣板代碼和更少的認(rèn)知成本,來擁抱 Redux 背后的簡單哲學(xué)。
你的點(diǎn)贊是我持續(xù)分享好東西的動力,歡迎點(diǎn)贊!
歡迎加入前端大家庭,里面會經(jīng)常分享一些技術(shù)資源。文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/109539.html
摘要:本周精讀內(nèi)容是重新思考。數(shù)據(jù)流對數(shù)據(jù)緩存,性能優(yōu)化,開發(fā)體驗優(yōu)化都有進(jìn)一步施展的空間,擁抱插件生態(tài)是一個良好的發(fā)展方向。 本周精讀內(nèi)容是 《重新思考 Redux》。 1 引言 《重新思考 Redux》是 rematch 作者 Shawn McKay 寫的一篇干貨軟文。 dva 之后,有許多基于 redux 的狀態(tài)管理框架,但大部分都很局限,甚至是倒退。但直到看到了 rematch,總算...
摘要:相關(guān)狀態(tài)父組件傳遞給子組件的狀態(tài)。外部狀態(tài)狀態(tài)是可以從視圖庫中移出來的,然后可以使用提供者消費(fèi)者模式把狀態(tài)重新連接回視圖庫。重新設(shè)計在我看來,重寫是有其必要性的,至少有以下個方面可以改進(jìn)得更友好。 Redux 學(xué)習(xí)起來很困難?寫起代碼來很啰嗦?一起來看看 Rematch 的作者對 Redux 的思考和簡化吧~ 原文:《Redesigning Redux》, Shawn McKay 都過...
摘要:現(xiàn)已存在許多成熟的狀態(tài)管理解決方案,還有基于的但對于我個人來說,理想的狀態(tài)管理工具只需同時滿足兩個特點(diǎn)簡單易用,并且適合中大型項目完美地支持要做到這兩點(diǎn)其實并不簡單。所以我決定自己造一個可能是基于和最好的狀態(tài)管理工具 現(xiàn)已存在許多成熟的狀態(tài)管理解決方案:Redux、Mobx、Mobx-state-tree,還有基于 Redux 的 Dva.js、Rematch... 但對于我個人來說,...
摘要:一個高仿的掘金,大部分是按照掘金的來實現(xiàn)的,個別地方就根據(jù)自己想法修修改改,只做了移動端的部分,還做的部分就要花太多時間了,支持服務(wù)端渲染等,寫這個項目主要是對近幾個月所學(xué)的技術(shù)做個實踐,看看有哪里還有不足,以及在實際開發(fā)的時候會踩到哪些 react-juejin 一個高仿的掘金,大部分是按照掘金的ui來實現(xiàn)的,個別地方就根據(jù)自己想法修修改改,只做了移動端的部分,還做pc的部分就要花太...
摘要:多端統(tǒng)一開發(fā)框架優(yōu)秀學(xué)習(xí)資源匯總官方資源項目倉庫官方文檔項目倉庫官方文檔微信小程序官方文檔百度智能小程序官方文檔支付寶小程序官方文檔字節(jié)跳動小程序官方文檔文章教程不敢閱讀包源碼帶你揭秘背后的哲學(xué)從到構(gòu)建適配不同端微信小程序等的應(yīng)用小程序最 Awesome Taro 多端統(tǒng)一開發(fā)框架 Taro 優(yōu)秀學(xué)習(xí)資源匯總 showImg(https://segmentfault.com/img/r...
閱讀 1474·2021-11-22 13:54
閱讀 4411·2021-09-22 15:56
閱讀 1853·2021-09-03 10:30
閱讀 1349·2021-09-03 10:30
閱讀 2106·2019-08-30 15:55
閱讀 1877·2019-08-30 14:13
閱讀 2084·2019-08-29 15:19
閱讀 2394·2019-08-28 18:13