摘要:是狀態(tài)容器,提供可預(yù)測(cè)化的狀態(tài)管理。一般我們會(huì)使用一個(gè)常量來(lái)表示對(duì)應(yīng)的值。作為純函數(shù),內(nèi)部不建議使用任何有副作用的操作,比如操作外部的變量,任何導(dǎo)致相同輸入但輸出卻不一致的操作。結(jié)合,其他類庫(kù),開(kāi)發(fā)步驟莫不如此。
Redux 是 JavaScript 狀態(tài)容器, 提供可預(yù)測(cè)化的狀態(tài)管理。
那什么是可以預(yù)測(cè)化,我的理解就是根據(jù)一個(gè)固定的輸入,必然會(huì)得到一個(gè)固定的結(jié)果。
redux是專門(mén)為react開(kāi)發(fā)的,但并不是只能用于react,可以用于任何界面庫(kù)。
動(dòng)機(jī)隨著單頁(yè)面應(yīng)用的普及,web app內(nèi)部需要管理的狀態(tài)越來(lái)越多,這些狀態(tài)可能來(lái)自服務(wù)器端,用戶輸入的數(shù)據(jù),用戶交互數(shù)據(jù),當(dāng)前UI狀態(tài),本地的緩存數(shù)據(jù)等等。如何能夠有條理的管理這些數(shù)據(jù),成為前端開(kāi)發(fā)中一個(gè)難題。
核心概念 三大原則 單一數(shù)據(jù)源使用redux的程序,所有的state都存儲(chǔ)在一個(gè)單一的數(shù)據(jù)源store內(nèi)部,類似一個(gè)巨大的對(duì)象樹(shù)。
state是只讀的state是只讀的,能改變state的唯一方式是通過(guò)觸發(fā)action來(lái)修改
使用純函數(shù)執(zhí)行修改為了描述 action 如何改變 state tree , 你需要編寫(xiě) reducers。
reducers是一些純函數(shù),接口當(dāng)前state和action。只需要根據(jù)action,返回對(duì)應(yīng)的state。而且必須要有返回。
一個(gè)函數(shù)的返回結(jié)果只依賴于它的參數(shù),并且在執(zhí)行過(guò)程里面沒(méi)有副作用,我們就把這個(gè)函數(shù)叫做純函數(shù)
基礎(chǔ) action顧名思義,action就是動(dòng)作,也就是通過(guò)動(dòng)作來(lái)修改state的值。也是修改store的唯一途徑。
action本質(zhì)上就是一個(gè)普通js對(duì)象,我們約定這個(gè)對(duì)象必須有一個(gè)字段type,來(lái)表示我們的動(dòng)作名稱。一般我們會(huì)使用一個(gè)常量來(lái)表示type對(duì)應(yīng)的值。
此外,我們還會(huì)把希望state變成什么樣子的對(duì)應(yīng)的值通過(guò)action傳進(jìn)來(lái),那么這里action可能會(huì)類似這樣子的
{ type: "TOGGLE_TODO", index: 5 }Reducer
Action 只是描述了有事情發(fā)生了這件事實(shí),但并沒(méi)有說(shuō)明要做哪些改變,這正是reducer需要做的事情。
Reducer作為純函數(shù),內(nèi)部不建議使用任何有副作用的操作,比如操作外部的變量,任何導(dǎo)致相同輸入但輸出卻不一致的操作。
如果我們的reducer比較多,比較復(fù)雜,我們不能把所有的邏輯都放到一個(gè)reducer里面去處理,這個(gè)時(shí)候我們就需要拆分reducer。
幸好,redux提供了一個(gè)api就是combineReducers Api。
storestore是redux應(yīng)用的唯一數(shù)據(jù)源,我們調(diào)用createStore Api創(chuàng)建store。
脫離react的redux案例 store,reducer基礎(chǔ)使用第一步搭建開(kāi)發(fā)環(huán)境,這里不介紹了,參考上一篇文章 手把手教會(huì)使用react開(kāi)發(fā)日歷組件,搭建環(huán)境部分
搭建好環(huán)境切換到目錄下面
npm install redux --save
把index.tsx修改為之下代碼。
import { createStore, combineReducers, applyMiddleware } from "redux" var simpleReducer = function(state = {}, action) { return { user: { name: "redux" } } } var store = createStore(simpleReducer) console.log(store.getState())
我們看到控制臺(tái)打印出來(lái)的一個(gè)包含user信息的這么一個(gè)對(duì)象。
我們使用到了幾個(gè)api? createStore創(chuàng)建store,store.getState()獲取store,也就是唯一數(shù)據(jù)源的根節(jié)點(diǎn)。
上文我們也講過(guò),action的情況可能會(huì)比較多,redux也提供了combineReducers Api。如果我們有多個(gè)reducer,我們就可以使用起來(lái)了。
那我們創(chuàng)建多個(gè)reducer測(cè)試一下,代碼如下:
import { createStore, combineReducers, applyMiddleware } from "redux" function user(state = {name: "redux"}, action) { switch (action.type) { case "CHANGE_NAME": return { ...state, name: action.name } } return state } function project(state = {name: "min-react"}, action) { switch (action.type) { case "CHANGE_NAME": return { ...state, name: action.name } } return state } var rootReducer = combineReducers({ user, project }) var store = createStore(rootReducer) console.log(store.getState())
如我們所預(yù)料一樣,我們得到擁有兩個(gè)字段的根store。
結(jié)合view使用第一步我們把html改造成這個(gè)樣子,新增了一點(diǎn)標(biāo)簽
Document
第二步,修改index.tsx,如下
import { createStore, combineReducers, applyMiddleware } from "redux" import { func } from "prop-types" function user(state = {name: "redux"}, action) { switch (action.type) { case "CHANGE_USER_NAME": return { ...state, name: action.name } } return state } function project(state = {name: "min-react"}, action) { switch (action.type) { case "CHANGE_PROJECT_NAME": return { ...state, name: action.name } } return state } var rootReducer = combineReducers({ user, project }) var store = createStore(rootReducer) function render(state = store.getState()) { var $userName = document.getElementById("userName") $userName.innerHTML = state.user.name } render() console.log(store.getState())
我們看到頁(yè)面正確的顯示了我們user的名稱。下一步我們需要做的就是通過(guò)用戶的操作,改變store的值,進(jìn)而觸發(fā)view的更新。
于是我們新增了這塊代碼:
store.subscribe(function() { render() }) // 綁定用戶事件 var $userNameInput = document.getElementById("userNameInput") var userNameButton = document.getElementById("userNameButton") userNameButton.onclick = function() { var value = $userNameInput.value store.dispatch({ type: "CHANGE_USER_NAME", name: value }) }
我們看到保存之后,當(dāng)我們輸入值之后,點(diǎn)擊更改,頁(yè)面的值隨著改變。
但是控制臺(tái)報(bào)了一個(gè)錯(cuò)誤,TS2339: Property "value" does not exist on type "HTMLElement".,這是由于typescript強(qiáng)類型校驗(yàn)沒(méi)通過(guò)導(dǎo)致的。只要加這段代碼就好了
var $userNameInput = document.getElementById("userNameInput") as HTMLInputElement
看到了吧,redux就是這么簡(jiǎn)單。
其他所有上層應(yīng)用,都是在此基礎(chǔ)上開(kāi)發(fā)的,所以開(kāi)發(fā)一個(gè)redux應(yīng)用的步驟就是
定義action和與之對(duì)應(yīng)的reducer
監(jiān)聽(tīng)store的變化,提供回調(diào)函數(shù)
dispatch一個(gè)action,等待好運(yùn)發(fā)生。
結(jié)合react,其他view類庫(kù),開(kāi)發(fā)步驟莫不如此。
高級(jí)應(yīng)用 異步action我們也看到了,我們的reducer只能做同步應(yīng)用,如果我們需要在reducer,做一些延遲操作,可怎么辦
社區(qū)已經(jīng)有成熟的類庫(kù)做這件事件
npm install redux-thunk --save
redux本身已經(jīng)提高了很好的擴(kuò)展機(jī)制,就是中間件。這點(diǎn)很類似express的中間件。
//引入新的類庫(kù) import { createStore, combineReducers, applyMiddleware, compose } from "redux" import thunk from "redux-thunk" ... //store部分做如下修改 const finalCreateStore = compose(applyMiddleware(thunk))(createStore) const store = finalCreateStore(rootReducer, {})
redux-thunk的作用就是讓dispatch方法不僅僅只接收action對(duì)象,還可以包含一個(gè)方法。我們可以在這個(gè)方法內(nèi)部去調(diào)用異步代碼
我們把dom事件部分做了如下改造
userNameButton.onclick = function() { var value = $userNameInput.value store.dispatch(function(dispatch, getState) { setTimeout(() => { dispatch({ type: "CHANGE_USER_NAME", name: value }) }, 2000) }) }
可以看到頁(yè)面元素確實(shí)在2s之后發(fā)生了變化,實(shí)際業(yè)務(wù)中啊,我們這里可以做一些異步操作。
至于redux原理,以及源碼和中間件的源碼講解可以參照我的另外一篇文章 閱讀redux源碼
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/97555.html
摘要:作為一個(gè)狀態(tài)樹(shù),來(lái)對(duì)狀態(tài)進(jìn)行管理。而對(duì)于組件來(lái)說(shuō),你只要一個(gè)就好了。好了,邏輯都明白了,接下來(lái)分析下內(nèi)部機(jī)制就有基礎(chǔ)了。一探分清一般我們的都是配合使用,但是和只是合作關(guān)系,并沒(méi)有血緣關(guān)系。這樣的就相當(dāng)于通過(guò)把和連接起來(lái)了。 導(dǎo)語(yǔ) 一開(kāi)看redux的時(shí)候還是比較蒙的,感覺(jué)比較繞,但是又好像是那么回事,接觸一個(gè)新概念的時(shí)候可能都是如此,多去接觸就熟悉了,今天就來(lái)分享下redux的三大核心為...
摘要:相關(guān)狀態(tài)父組件傳遞給子組件的狀態(tài)。外部狀態(tài)狀態(tài)是可以從視圖庫(kù)中移出來(lái)的,然后可以使用提供者消費(fèi)者模式把狀態(tài)重新連接回視圖庫(kù)。重新設(shè)計(jì)在我看來(lái),重寫(xiě)是有其必要性的,至少有以下個(gè)方面可以改進(jìn)得更友好。 Redux 學(xué)習(xí)起來(lái)很困難?寫(xiě)起代碼來(lái)很啰嗦?一起來(lái)看看 Rematch 的作者對(duì) Redux 的思考和簡(jiǎn)化吧~ 原文:《Redesigning Redux》, Shawn McKay 都過(guò)...
摘要:在幾天前發(fā)布了新版本,被合入。但是在版本迭代的背后很多有趣的設(shè)計(jì)值得了解。參數(shù)處理這項(xiàng)改動(dòng)由提出。對(duì)透明化處理中的,達(dá)到將包裹起來(lái)的目的。對(duì)的凍結(jié)認(rèn)為,在中使用和方法是一種反模式。尤其是這樣的新,某些開(kāi)發(fā)者認(rèn)為將逐漸取代。 showImg(https://segmentfault.com/img/remote/1460000014571148); Redux 在幾天前(2018.04....
閱讀 1706·2021-09-22 15:25
閱讀 1624·2021-09-07 10:06
閱讀 3256·2019-08-30 15:53
閱讀 1155·2019-08-29 13:12
閱讀 3459·2019-08-29 13:07
閱讀 805·2019-08-28 18:19
閱讀 2353·2019-08-27 10:57
閱讀 1045·2019-08-26 13:29