正常redux流程 javascript
加入redux-saga以後的流程 java
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
//引入saga文件
import { rootSaga } from './rootSaga'
//使用 redux-saga 模塊的 createSagaMiddleware 工廠函數來建立一個 Saga middleware。
//運行 rootSaga 以前,咱們必須使用 applyMiddleware 將 middleware 鏈接至 Store。而後使用
const sagaMiddleware = createSagaMiddleware();
const middlewares = [ sagaMiddleware ];
const store = createStore(rootReducer, applyMiddleware(...middlewares));
sagaMiddleware.run(rootSaga);
複製代碼
sage提供了一些輔助函數,包裝了一些內部方法,用來在一些特定的action被髮起到store時派生任務ios
import { call, put } from 'redux-saga/effects'
export function* fetchData(action) {
try {
const data = yield call(Api.fetchUser, action.payload.url);
yield put({type: "FETCH_SUCCEEDED", data});
} catch (error) {
yield put({type: "FETCH_FAILED", error});
}
}
function* watchFetchData() {
yield* takeEvery('FETCH_REQUESTED', fetchData)
}
//有一種用法:監控全部的發起的action
yield takeEvery('*', fn)
複製代碼
takeEvery 容許多個 fetchData 實例同時啓動, 在某個特定時刻, 儘管以前還有一個或多個fetchData還沒有結束, 咱們仍是能夠啓動一個新的fetchData任務-->意思就是隻用調用了 FETCH_REQUESTED action的時候就會啓動 fetchData 任務.redux
function* watchFetchData() {
yield* takeLatest('FETCH_REQUESTED', fetchData)
}
複製代碼
在任什麼時候刻 takeLatest只容許一個 fetchData 任務在執行,而且這個任務是最後被啓動的那個,若是以前有一個任務再啓動的時候執行了fetchData , 那麼以前的任務會被自動取消 -- 能夠得到最後一次(最新)調用FETCH_REQUESTED action 獲得的結果.axios
sagas都是Generator函數實現,能夠用yield 對 js 對象來表達saga的邏輯,這些對象就是effect,api
//官方例子
import { takeEvery } from 'redux-saga/effects'
import Api from './path/to/api'
//監聽若是有一個調用PRODUCTS_REQUESTED 的action的話,就會匹配到第二個參數所表明的effect
function* watchFetchProducts() {
yield takeEvery('PRODUCTS_REQUESTED', fetchProducts)
}
//執行,獲取數據
//使用Generator 調用了Api.fetch,在Generator函數中,yield右面的任何表達式都會被求值,結果會被yield給調用者
function* fetchProducts() {
const products = yield Api.fetch('/products')
console.log(products)
}
//第二種方式
import { call } from 'redux-saga/effects'
//call(fn, ...args) 這個函數。與前面的例子不一樣的是,如今咱們不當即執行異步調用,相反,call
//建立了一條描述結果的信息就像在 Redux 裏你使用 action 建立器,建立一個將被 Store 執行的、描述 action 的純文本對象。
//call 建立一個純文本對象描述函數調用。redux-saga middleware 確保執行函數調用並在響應被 resolve 時恢復 generator
function* fetchProducts() {
const products = yield call(Api.fetch, '/products')
// ...
}
複製代碼
//這種方式是Generator獲取到了返回值,在調用dispatch
function* fetchProducts(dispatch) const products = yield call(Api.fetch, '/products') dispatch({ type: 'PRODUCTS_RECEIVED', products }) } import { call, put } from 'redux-saga/effects'
//...
function* fetchProducts() {
const products = yield call(Api.fetch, '/products')
// 建立並 yield 一個 dispatch Effect
yield put({ type: 'PRODUCTS_RECEIVED', products })
}
複製代碼
import Api from './path/to/api'
import { call, put } from 'redux-saga/effects'
function* fetchProducts() {
try {
const products = yield call(Api.fetch, '/products')
yield put({ type: 'PRODUCTS_RECEIVED', products })
}
catch(error) {
yield put({ type: 'PRODUCTS_REQUEST_FAILED', error })
}
}
複製代碼
使用 try/catch 的方式捕獲saga的錯誤信息數組
從 Saga 內觸發異步操做(Side Effect)老是由 yield 一些聲明式的 Effect 來完成的 , 一個 Saga 所作的其實是組合那些全部的 Effect,共同實現所需的控制流。使用上是用yield Effects的方式來完成,Effect包括併發
function* watchAndLog() {
while (true) {
const action = yield take('*')
const state = yield select()
}
}
take,它將會暫停 Generator 直到一個匹配的 action 被髮起了,watchAndLog 處於暫停狀態,直到任意的一個 action 被髮起。
複製代碼
fork一個任務,任務會在後臺啓動,調用者也能夠繼續它的流程,而不用等待被fork的任務執行結束 當咱們須要有併發操做的時候,使用call effect會阻塞saga的執行,使用fork就須要關心被阻塞,或者等待結果返回在繼續執行app
const result = yield fork (saga,param)
複製代碼
const [users, repos] = yield [
call(fetch, '/users'),
call(fetch, '/repos')
]
複製代碼
當須要同步執行多個任務,須要把yield一個包含了effect的數組,Generator將會阻塞,等全部的effect都執行完畢異步
//redux.connect所須要綁定到props上的action
function mapDispatchToProps(dispatch) {
return {
getHome: bindActionCreators(getHomeAdData, dispatch)
}
}
//一個 action creator
export function getHomeAdData(){
return {
type: actionTypes.HOME_AD_DATA,
}
}
//監聽action.type,而後出發後面的action
export default function* rootSaga () {
// 就在這個rootSaga裏面利用takeEvery去監聽action的type
yield takeEvery('HOME_AD_DATA', getHomeAdData);
yield takeEvery('GET_LIKE_LIST_DATA', getLikeListData);
}
//經過yield call Effect 獲取返回值,繼續下面操做
export function* getHomeAdData() {
let data = yield call(getAdData)
...
yield put({type:UPDATE_HOME_AD_DATA, data: dataArr})
}
export function getAdData() {
const result = axios.get('/api/homead')
return result
}
複製代碼