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