成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

一篇文章總結(jié)redux、react-redux、redux-saga

April / 1403人閱讀

摘要:編輯器頂層組件不就了嗎這就是。官方提供的綁定庫(kù)。具有高效且靈活的特性。在的中,可以使用或者等來(lái)監(jiān)聽(tīng)某個(gè),當(dāng)某個(gè)觸發(fā)后,可以使用發(fā)起異步操作,操作完成后使用函數(shù)觸發(fā),同步更新,從而完成整個(gè)的更新。

不就ok了嗎?這就是 react-redux。Redux 官方提供的 React 綁定庫(kù)。 具有高效且靈活的特性。

React Redux 將組件區(qū)分為 容器組件 和 UI 組件

    前者會(huì)處理邏輯

    后者只負(fù)責(zé)顯示和交互,內(nèi)部不處理邏輯,狀態(tài)完全由外部掌控

兩個(gè)核心

Provider

看我上邊那個(gè)代碼的頂層組件4個(gè)字。對(duì),你沒(méi)有猜錯(cuò)。這個(gè)頂級(jí)組件就是Provider,一般我們都將頂層組件包裹在Provider組件之中,這樣的話,所有組件就都可以在react-redux的控制之下了,但是store必須作為參數(shù)放到Provider組件中去

這個(gè)組件的目的是讓所有組件都能夠訪問(wèn)到Redux中的數(shù)據(jù)。

connect

這個(gè)才是react-redux中比較難的部分,我們?cè)敿?xì)解釋一下

首先,先記住下邊的這行代碼:

connect(mapStateToProps, mapDispatchToProps)(MyComponent)

mapStateToProps

這個(gè)單詞翻譯過(guò)來(lái)就是把state映射到props中去 ,其實(shí)也就是把Redux中的數(shù)據(jù)映射到React中的props中去。

舉個(gè)栗子:

const mapStateToProps = (state) => { return { // prop : state.xxx | 意思是將state中的某個(gè)數(shù)據(jù)映射到props中 foo: state.bar } }

然后渲染的時(shí)候就可以使用this.props.foo

class Foo extends Component { constructor(props){ super(props); } render(){ return( // 這樣子渲染的其實(shí)就是state.bar的數(shù)據(jù)了

this.props.foo
) } } Foo = connect()(Foo); export default Foo;

然后這樣就可以完成渲染了

mapDispatchToProps

這個(gè)單詞翻譯過(guò)來(lái)就是就是把各種dispatch也變成了props讓你可以直接使用

const mapDispatchToProps = (dispatch) => { // 默認(rèn)傳遞參數(shù)就是dispatch return { onClick: () => { dispatch({ type: "increatment" }); } }; }

class Foo extends Component { constructor(props){ super(props); } render(){ return( ) } } Foo = connect()(Foo); export default Foo;

組件也就改成了上邊這樣,可以直接通過(guò)this.props.onClick,來(lái)調(diào)用dispatch,這樣子就不需要在代碼中來(lái)進(jìn)行store.dispatch了

react-redux的基本介紹就到這里了

redux-saga

如果按照原始的redux工作流程,當(dāng)組件中產(chǎn)生一個(gè)action后會(huì)直接觸發(fā)reducer修改state,reducer又是一個(gè)純函數(shù),也就是不能再reducer中進(jìn)行異步操作;

而往往實(shí)際中,組件中發(fā)生的action后,在進(jìn)入reducer之前需要完成一個(gè)異步任務(wù),比如發(fā)送ajax請(qǐng)求后拿到數(shù)據(jù)后,再進(jìn)入reducer,顯然原生的redux是不支持這種操作的

這個(gè)時(shí)候急需一個(gè)中間件來(lái)處理這種業(yè)務(wù)場(chǎng)景,目前最優(yōu)雅的處理方式自然就是redux-saga

核心講解

1、Saga 輔助函數(shù)

redux-saga提供了一些輔助函數(shù),用來(lái)在一些特定的action 被發(fā)起到Store時(shí)派生任務(wù),下面我先來(lái)講解兩個(gè)輔助函數(shù):takeEverytakeLatest

takeEvery

takeEvery就像一個(gè)流水線的洗碗工,過(guò)來(lái)一個(gè)臟盤(pán)子就直接執(zhí)行后面的洗碗函數(shù),一旦你請(qǐng)了這個(gè)洗碗工他會(huì)一直執(zhí)行這個(gè)工作,絕對(duì)不會(huì)停止接盤(pán)子的監(jiān)聽(tīng)過(guò)程和觸發(fā)洗盤(pán)子函數(shù)

例如:每次點(diǎn)擊 按鈕去Fetch獲取數(shù)據(jù)時(shí)時(shí),我們發(fā)起一個(gè) FETCH_REQUESTED 的 action。 我們想通過(guò)啟動(dòng)一個(gè)任務(wù)從服務(wù)器獲取一些數(shù)據(jù),來(lái)處理這個(gè)action,類(lèi)似于

window.addEventLister("xxx",fn)

當(dāng)dispatch xxx的時(shí)候,就會(huì)執(zhí)行fn方法,

首先我們創(chuàng)建一個(gè)將執(zhí)行異步 action 的任務(wù)(也就是上邊的fn):

// put:你就認(rèn)為put就等于 dispatch就可以了; // call:可以理解為實(shí)行一個(gè)異步函數(shù),是阻塞型的,只有運(yùn)行完后面的函數(shù),才會(huì)繼續(xù)往下; // 在這里可以片面的理解為async中的await!但寫(xiě)法直觀多了! import { call, put } from "redux-saga/effects" export function* fetchData(action) { try { const apiAjax = (params) => fetch(url, params); const data = yield call(apiAjax); yield put({type: "FETCH_SUCCEEDED", data}); } catch (error) { yield put({type: "FETCH_FAILED", error}); } }

然后在每次 FETCH_REQUESTED action 被發(fā)起時(shí)啟動(dòng)上面的任務(wù),也就相當(dāng)于每次觸發(fā)一個(gè)名字為 FETCH_REQUESTED 的action就會(huì)執(zhí)行上邊的任務(wù),代碼如下

import { takeEvery } from "redux-saga" function* watchFetchData() { yield* takeEvery("FETCH_REQUESTED", fetchData) }

注意:上面的 takeEvery 函數(shù)可以使用下面的寫(xiě)法替換

function* watchFetchData() { while(true){ yield take("FETCH_REQUESTED"); yield fork(fetchData); } }

takeLatest

在上面的例子中,takeEvery 允許多個(gè) fetchData 實(shí)例同時(shí)啟動(dòng),在某個(gè)特定時(shí)刻,我們可以啟動(dòng)一個(gè)新的 fetchData 任務(wù), 盡管之前還有一個(gè)或多個(gè) fetchData 尚未結(jié)束

如果我們只想得到最新那個(gè)請(qǐng)求的響應(yīng)(例如,始終顯示最新版本的數(shù)據(jù)),我們可以使用 takeLatest 輔助函數(shù)

import { takeLatest } from "redux-saga" function* watchFetchData() { yield* takeLatest("FETCH_REQUESTED", fetchData) }

和takeEvery不同,在任何時(shí)刻 takeLatest 只允許執(zhí)行一個(gè) fetchData 任務(wù),并且這個(gè)任務(wù)是最后被啟動(dòng)的那個(gè),如果之前已經(jīng)有一個(gè)任務(wù)在執(zhí)行,那之前的這個(gè)任務(wù)會(huì)自動(dòng)被取消

2、Effect Creators

redux-saga框架提供了很多創(chuàng)建effect的函數(shù),下面我們就來(lái)簡(jiǎn)單的介紹下開(kāi)發(fā)中最常用的幾種

take(pattern)

put(action)

call(fn, ...args)

fork(fn, ...args)

select(selector, ...args)

take(pattern)

take函數(shù)可以理解為監(jiān)聽(tīng)未來(lái)的action,它創(chuàng)建了一個(gè)命令對(duì)象,告訴middleware等待一個(gè)特定的action, Generator會(huì)暫停,直到一個(gè)與pattern匹配的action被發(fā)起,才會(huì)繼續(xù)執(zhí)行下面的語(yǔ)句,也就是說(shuō),take是一個(gè)阻塞的 effect

用法:

function* watchFetchData() { while(true) { // 監(jiān)聽(tīng)一個(gè)type為 "FETCH_REQUESTED" 的action的執(zhí)行,直到等到這個(gè)Action被觸發(fā),才會(huì)接著執(zhí)行下面的 yield fork(fetchData) 語(yǔ)句 yield take("FETCH_REQUESTED"); yield fork(fetchData); } }

put(action)

put函數(shù)是用來(lái)發(fā)送action的 effect,你可以簡(jiǎn)單的把它理解成為redux框架中的dispatch函數(shù),當(dāng)put一個(gè)action后,reducer中就會(huì)計(jì)算新的state并返回,注意: put 也是阻塞 effect

用法:

export function* toggleItemFlow() { let list = [] // 發(fā)送一個(gè)type為 "UPDATE_DATA" 的Action,用來(lái)更新數(shù)據(jù),參數(shù)為 `data:list` yield put({ type: actionTypes.UPDATE_DATA, data: list }) }

call(fn, ...args)

call函數(shù)你可以把它簡(jiǎn)單的理解為就是可以調(diào)用其他函數(shù)的函數(shù),它命令 middleware 來(lái)調(diào)用fn 函數(shù), args為函數(shù)的參數(shù),注意: fn 函數(shù)可以是一個(gè) Generator 函數(shù),也可以是一個(gè)返回 Promise 的普通函數(shù),call 函數(shù)也是阻塞 effect

用法:

export const delay = ms => new Promise(resolve => setTimeout(resolve, ms)) export function* removeItem() { try { // 這里call 函數(shù)就調(diào)用了 delay 函數(shù),delay 函數(shù)為一個(gè)返回promise 的函數(shù) return yield call(delay, 500) } catch (err) { yield put({type: actionTypes.ERROR}) } }

fork(fn, ...args)

fork 函數(shù)和 call 函數(shù)很像,都是用來(lái)調(diào)用其他函數(shù)的,但是fork函數(shù)是非阻塞函數(shù),也就是說(shuō),程序執(zhí)行完 yield fork(fn, args) 這一行代碼后,會(huì)立即接著執(zhí)行下一行代碼語(yǔ)句,而不會(huì)等待fn函數(shù)返回結(jié)果后,在執(zhí)行下面的語(yǔ)句

用法:

import { fork } from "redux-saga/effects" export default function* rootSaga() { // 下面的四個(gè) Generator 函數(shù)會(huì)一次執(zhí)行,不會(huì)阻塞執(zhí)行 yield fork(addItemFlow) yield fork(removeItemFlow) yield fork(toggleItemFlow) yield fork(modifyItem) }

select(selector, ...args)

select 函數(shù)是用來(lái)指示 middleware調(diào)用提供的選擇器獲取Store上的state數(shù)據(jù),你也可以簡(jiǎn)單的把它理解為redux框架中獲取store上的 state數(shù)據(jù)一樣的功能store.getState()

用法:

export function* toggleItemFlow() { // 通過(guò) select effect 來(lái)獲取 全局 state上的 `getTodoList` 中的 list let tempList = yield select(state => state.getTodoList.list) }

一個(gè)具體的實(shí)例

**index.js **

import React from "react"; import ReactDOM from "react-dom"; import {createStore, applyMiddleware} from "redux" import createSagaMiddleware from "redux-saga" import rootSaga from "./sagas" import Counter from "./Counter" import rootReducer from "./reducers" const sagaMiddleware = createSagaMiddleware() // 創(chuàng)建了一個(gè)saga中間件實(shí)例 // 下邊這句話和下邊的兩行代碼創(chuàng)建store的方式是一樣的 // const store = createStore(reducers,applyMiddlecare(middlewares)) const createStoreWithMiddleware = applyMiddleware(middlewares)(createStore) const store = createStoreWithMiddleware(rootReducer) sagaMiddleware.run(rootSaga) const action = type => store.dispatch({ type }) function render() { ReactDOM.render( action("INCREMENT")} onDecrement={() => action("DECREMENT")} onIncrementAsync={() => action("INCREMENT_ASYNC")} />, document.getElementById("root") ) } render() store.subscribe(render)

sagas.js

import { put, call, take,fork } from "redux-saga/effects"; import { takeEvery, takeLatest } from "redux-saga" export const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); function* incrementAsync() { // 延遲 1s 在執(zhí)行 + 1操作 yield call(delay, 1000); yield put({ type: "INCREMENT" }); } export default function* rootSaga() { // while(true){ // yield take("INCREMENT_ASYNC"); // yield fork(incrementAsync); // } // 下面的寫(xiě)法與上面的寫(xiě)法上等效 yield* takeEvery("INCREMENT_ASYNC", incrementAsync) }

reducer.js

export default function counter(state = 0, action) { switch (action.type) { case "INCREMENT": return state + 1 case "DECREMENT": return state - 1 case "INCREMENT_ASYNC": return state default: return state } }

從上面的代碼結(jié)構(gòu)可以看出,redux-saga的使用方式還是比較簡(jiǎn)單的,相比較之前的redux框架的CounterApp,多了一個(gè)sagas的文件,reducers文件還是之前的使用方式

redux-saga基本用法總結(jié):

    使用 createSagaMiddleware 方法創(chuàng)建 saga 的 Middleware ,然后在創(chuàng)建的 redux 的 store 時(shí),使用 applyMiddleware 函數(shù)將創(chuàng)建的 saga Middleware 實(shí)例綁定到 store 上,最后可以調(diào)用 saga Middleware 的 run 函數(shù)來(lái)執(zhí)行某個(gè)或者某些 Middleware 。

    在 saga 的 Middleware 中,可以使用 takeEvery 或者 takeLatest 等 API 來(lái)監(jiān)聽(tīng)某個(gè) action ,當(dāng)某個(gè) action 觸發(fā)后, saga 可以使用 call 發(fā)起異步操作,操作完成后使用 put 函數(shù)觸發(fā) action ,同步更新 state ,從而完成整個(gè) State 的更新。


ok,故事到這里就接近尾聲了,以上主要介紹了redux,react-redux和redux-saga目前redux全家桶主流的一些產(chǎn)品,接下來(lái),主要會(huì)產(chǎn)出一下根據(jù)源碼,手寫(xiě)一下redux和react-redux的輪子

希望各位大佬點(diǎn)贊,關(guān)注,鼓勵(lì)一下,不足之處,還望斧正~

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/6659.html

相關(guān)文章

  • React技術(shù)棧實(shí)現(xiàn)XXX點(diǎn)評(píng)App demo

    摘要:項(xiàng)目的架構(gòu)也是最近在各種探討研究。還求大神多指點(diǎn)項(xiàng)目技術(shù)總結(jié)技術(shù)棧項(xiàng)目結(jié)構(gòu)探究初體驗(yàn)關(guān)于項(xiàng)目中的配置說(shuō)明項(xiàng)目簡(jiǎn)單說(shuō)明開(kāi)發(fā)這一套,我個(gè)人的理解是體現(xiàn)的是代碼分層職責(zé)分離的編程思想邏輯與視圖嚴(yán)格區(qū)分。前端依舊使用技術(shù)棧完成。 項(xiàng)目地址:https://github.com/Nealyang/R...技術(shù)棧:react、react-router4.x 、 react-redux 、 webp...

    wslongchen 評(píng)論0 收藏0
  • Redux-saga 初探

    摘要:背景項(xiàng)目用的是全家桶,之前有同事用改進(jìn)了一波,一直都沒(méi)去研究。這次的打算寫(xiě)一個(gè)輸入框,輸入拼音會(huì)返回對(duì)應(yīng)的城市列表。 背景 項(xiàng)目用的是react全家桶, 之前有同事用redux-saga 改進(jìn)了一波, 一直都沒(méi)去研究。 前幾天趁有空,也去學(xué)習(xí)了下, 寫(xiě)了個(gè)簡(jiǎn)單的demo練練手, 在這里簡(jiǎn)單分享一下。 這次的demo打算寫(xiě)一個(gè)輸入框,輸入拼音會(huì)返回對(duì)應(yīng)的城市列表。并盡可能多的使用redu...

    yuanxin 評(píng)論0 收藏0
  • react 前端項(xiàng)目技術(shù)選型、開(kāi)發(fā)工具、周邊生態(tài)

    摘要:更多參考通過(guò)庫(kù)掌握函數(shù)組件有些時(shí)候,我們想要?jiǎng)討B(tài)的加載一些組件按需加載,比如在一個(gè)單頁(yè)面應(yīng)用中頁(yè)面的組件頁(yè)面的組件頁(yè)面的組件只有真正要實(shí)例化當(dāng)前頁(yè)面的時(shí)候,才會(huì)去加載相應(yīng)的組件。 react 前端項(xiàng)目技術(shù)選型、開(kāi)發(fā)工具、周邊生態(tài) 聲明:這不是一篇介紹 React 基礎(chǔ)知識(shí)的文章,需要熟悉 React 相關(guān)知識(shí) 主架構(gòu):react, react-router, redux, redux...

    hersion 評(píng)論0 收藏0
  • react 前端項(xiàng)目技術(shù)選型、開(kāi)發(fā)工具、周邊生態(tài)

    摘要:更多參考通過(guò)庫(kù)掌握函數(shù)組件有些時(shí)候,我們想要?jiǎng)討B(tài)的加載一些組件按需加載,比如在一個(gè)單頁(yè)面應(yīng)用中頁(yè)面的組件頁(yè)面的組件頁(yè)面的組件只有真正要實(shí)例化當(dāng)前頁(yè)面的時(shí)候,才會(huì)去加載相應(yīng)的組件。 react 前端項(xiàng)目技術(shù)選型、開(kāi)發(fā)工具、周邊生態(tài) 聲明:這不是一篇介紹 React 基礎(chǔ)知識(shí)的文章,需要熟悉 React 相關(guān)知識(shí) 主架構(gòu):react, react-router, redux, redux...

    kidsamong 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<