小編給大家分享一下redux、react-redux、redux-saga的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
成都創(chuàng)新互聯(lián)公司專注于濂溪企業(yè)網(wǎng)站建設(shè),成都響應(yīng)式網(wǎng)站建設(shè),商城網(wǎng)站定制開(kāi)發(fā)。濂溪網(wǎng)站建設(shè)公司,為濂溪等地區(qū)提供建站服務(wù)。全流程按需定制開(kāi)發(fā),專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,成都創(chuàng)新互聯(lián)公司專業(yè)和態(tài)度為您提供的服務(wù)
前言
首先,本篇文章要求您對(duì)js,react等知識(shí)有一定的了解,如果不曾了解,建議您先看一下:React精髓!一篇全概括(急速)
React有props和state:
props意味著父級(jí)分發(fā)下來(lái)的屬性
state意味著組件內(nèi)部可以自行管理的狀態(tài),并且整個(gè)React沒(méi)有數(shù)據(jù)向上回溯的能力,這就是react的單向數(shù)據(jù)流
這就意味著如果是一個(gè)數(shù)據(jù)狀態(tài)非常復(fù)雜的應(yīng)用,更多的時(shí)候發(fā)現(xiàn)React根本無(wú)法讓兩個(gè)組件互相交流,使用對(duì)方的數(shù)據(jù),react的通過(guò)層級(jí)傳遞數(shù)據(jù)的這種方法是非常難受的,這個(gè)時(shí)候,迫切需要一個(gè)機(jī)制,把所有的state集中到組件頂部,能夠靈活的將所有state各取所需的分發(fā)給所有的組件,是的,這就是redux
簡(jiǎn)介
redux是的誕生是為了給 React 應(yīng)用提供「可預(yù)測(cè)化的狀態(tài)管理」機(jī)制。
Redux會(huì)將整個(gè)應(yīng)用狀態(tài)(其實(shí)也就是數(shù)據(jù))存儲(chǔ)到到一個(gè)地方,稱為store
這個(gè)store里面保存一棵狀態(tài)樹(shù)(state tree)
組件改變state的唯一方法是通過(guò)調(diào)用store的dispatch方法,觸發(fā)一個(gè)action,這個(gè)action被對(duì)應(yīng)的reducer處理,于是state完成更新
組件可以派發(fā)(dispatch)行為(action)給store,而不是直接通知其它組件
其它組件可以通過(guò)訂閱store中的狀態(tài)(state)來(lái)刷新自己的視圖
使用步驟
創(chuàng)建reducer
可以使用單獨(dú)的一個(gè)reducer,也可以將多個(gè)reducer合并為一個(gè)reducer,即:combineReducers()
action發(fā)出命令后將state放入reucer加工函數(shù)中,返回新的state,對(duì)state進(jìn)行加工處理
創(chuàng)建action
用戶是接觸不到state的,只能有view觸發(fā),所以,這個(gè)action可以理解為指令,需要發(fā)出多少動(dòng)作就有多少指令
action是一個(gè)對(duì)象,必須有一個(gè)叫type的參數(shù),定義action類型
創(chuàng)建的store,使用createStore方法
store 可以理解為有多個(gè)加工機(jī)器的總工廠
提供subscribe,dispatch,getState這些方法。
按步驟手把手實(shí)戰(zhàn)。
上述步驟,對(duì)應(yīng)的序號(hào),我會(huì)在相關(guān)代碼標(biāo)出
npm install redux -S // 安裝
import { createStore } from 'redux' // 引入
const reducer = (state = {count: 0}, action) => {----------> ⑴
switch (action.type){
case 'INCREASE': return {count: state.count + 1};
case 'DECREASE': return {count: state.count - 1};
default: return state;
}
}
const actions = {---------->⑵
increase: () => ({type: 'INCREASE'}),
decrease: () => ({type: 'DECREASE'})
}
const store = createStore(reducer);---------->⑶
store.subscribe(() =>
console.log(store.getState())
);
store.dispatch(actions.increase()) // {count: 1}
store.dispatch(actions.increase()) // {count: 2}
store.dispatch(actions.increase()) // {count: 3}自己畫了一張非常簡(jiǎn)陋的流程圖,方便理解redux的工作流程

剛開(kāi)始就說(shuō)了,如果把store直接集成到React應(yīng)用的頂層props里面,只要各個(gè)子組件能訪問(wèn)到頂層props就行了,比如這樣:
<頂層組件 store={store}>
<App />
</頂層組件>不就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組件中去
<Provider store = {store}>
<App />
<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ù)了
<div>this.props.foo</div>
)
}
}
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(
<button onClick = {this.props.onClick}>點(diǎn)擊increase</button>
)
}
}
Foo = connect()(Foo);
export default Foo;組件也就改成了上邊這樣,可以直接通過(guò)this.props.onClick,來(lái)調(diào)用dispatch,這樣子就不需要在代碼中來(lái)進(jìn)行store.dispatch了
react-redux的基本介紹就到這里了
如果按照原始的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ù):takeEvery 和 takeLatest
takeEvery
takeEvery就像一個(gè)流水線的洗碗工,過(guò)來(lái)一個(gè)臟盤子就直接執(zhí)行后面的洗碗函數(shù),一旦你請(qǐng)了這個(gè)洗碗工他會(huì)一直執(zhí)行這個(gè)工作,絕對(duì)不會(huì)停止接盤子的監(jiān)聽(tīng)過(guò)程和觸發(fā)洗盤子函數(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,類似于
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!但寫法直觀多了!
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ù)可以使用下面的寫法替換
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(
<Counter
value={store.getState()}
onIncrement={() => 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);
// }
// 下面的寫法與上面的寫法上等效
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 的更新。
以上是“redux、react-redux、redux-saga的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
文章名稱:redux、react-redux、redux-saga的示例分析
網(wǎng)頁(yè)鏈接:http://chinadenli.net/article46/jijoeg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)網(wǎng)站建設(shè)、定制網(wǎng)站、移動(dòng)網(wǎng)站建設(shè)、外貿(mào)建站、網(wǎng)站設(shè)計(jì)、網(wǎng)站策劃
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)