如果没有中间件,store.dispatch只能接收一个普通对象作为action。在处理异步action时,我们需要在异步回调或者promise函数then内,async函数await之后dispatch。
dispatch({ type:'before-load' }) fetch('http://myapi.com/${userId}').then({ response =>dispatch({ type:'load', payload:response }) })
这样做确实可以解决问题,特别是在小型项目中,高效,可读性强。 但缺点是需要在组件中写大量的异步逻辑代码,不能将异步过程(例如异步获取数据)与dispatch抽象出来进行复用。而采用类似redux-thunk之类的中间件可以使得dispatch能够接收不仅仅是普通对象作为action。例如:
function load(userId){ return function(dispatch,getState){ dispatch({ type:'before-load' }) fetch('http://myapi.com/${userId}').then({ response =>dispatch({ type:'load', payload:response }) }) } } //使用方式 dispatch(load(userId))
使用中间件可以让你采用自己方便的方式dispatch异步action,下面介绍常见的三种。
1. redux-thunk
function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; } const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware; export default thunk;
2. redux-promise
使用redux-promise可以将action或者action的payload写成promise形式。 源码:
export default function promiseMiddleware({ dispatch }) { return next => action => { if (!isFSA(action)) { return isPromise(action) "color: #ff0000">3. Redux-saga
redux-saga 是一个用于管理应用程序 Side Effect(副作用,例如异步获取数据,访问浏览器缓存等)的 library,它的目标是让副作用管理更容易,执行更高效,测试更简单,在处理故障时更容易
3.1 基本使用
import { call, put, takeEvery, takeLatest} from 'redux-saga/effects'; //复杂的异步流程操作 function* fetchUser(action){ try{ const user = yield call(API.fetchUser, action.payload); yield put({type:"USER_FETCH_SUCCEEDED",user:user}) }catch(e){ yield put({type:"USER_FETCH_FAILED",message:e.message}) } } //监听dispatch,调用相应函数进行处理 function* mainSaga(){ yield takeEvery("USER_FETCH_REQUESTED",fetchUser); } //在store中注入saga中间件 import {createStore,applyMiddleware} from 'redux'; import createSagaMiddleware from 'redux-saga'; import reducer from './reducers'; import mainSaga from './mainSaga'; const sagaMiddleware = createSagaMiddleware(); const store = createStore(reducer,initalState,applyMiddleware(sagaMiddleware)); sagaMiddleware.run(mainSaga)3.2 声明式effects,便于测试
为了测试方便,在generator中不立即执行异步调用,而是使用call、apply等effects创建一条描述函数调用的对象,saga中间件确保执行函数调用并在响应被resolve时恢复generator。
function* fetchProducts() { const products = yield Api.fetch('/products') dispatch({ type: 'PRODUCTS_RECEIVED', products }) } //便于测试 function* fetchProducts() { const products = yield call(Api.fetch, '/products') //便于测试dispatch yield put({ type: 'PRODUCTS_RECEIVED', products }) // ... } // Effect -> 调用 Api.fetch 函数并传递 `./products` 作为参数 { CALL: { fn: Api.fetch, args: ['./products'] } }3.3 构建复杂的控制流
saga可以通过使用effect创建器、effect组合器、saga辅助函数来构建复杂的控制流。
effect创建器:
- take:阻塞性effect,等待store中匹配的action或channel中的特定消息。
- put:非阻塞性effect,用来命令 middleware 向 Store 发起一个 action。
- call:阻塞性effect,用来命令 middleware 以参数 args 调用函数 fn。
- fork:非阻塞性effect,用来命令 middleware 以 非阻塞调用 的形式执行 fn
- select:非阻塞性effect,用来命令 middleware 在当前 Store 的 state 上调用指定的选择器
effect组合器:
race:阻塞性effect:用来命令 middleware 在多个 Effect 间运行 竞赛(Race)
function fetchUsersSaga { const { response, cancel } = yield race({ response: call(fetchUsers), cancel: take(CANCEL_FETCH) }) }
all: 当 array 或 object 中有阻塞型 effect 的时候阻塞,用来命令 middleware 并行地运行多个 Effect,并等待它们全部完成
function* mySaga() { const [customers, products] = yield all([ call(fetchCustomers), call(fetchProducts) ]) }
effect辅助函数:
takeEvery:非阻塞性effect,在发起(dispatch)到 Store 并且匹配 pattern 的每一个 action 上派生一个 saga
const takeEvery = (patternOrChannel, saga, ...args) => fork(function*() { while (true) { const action = yield take(patternOrChannel) yield fork(saga, ...args.concat(action)) } })
takeLatest:非阻塞性,在发起到 Store 并且匹配 pattern 的每一个 action 上派生一个 saga。并自动取消之前所有已经启动但仍在执行中的 saga 任务。
const takeLatest = (patternOrChannel, saga, ...args) => fork(function*() { let lastTask while (true) { const action = yield take(patternOrChannel) if (lastTask) { yield cancel(lastTask) // 如果任务已经结束,cancel 则是空操作 } lastTask = yield fork(saga, ...args.concat(action)) } })
throttle:非阻塞性,在 ms 毫秒内将暂停派生新的任务
const throttle = (ms, pattern, task, ...args) => fork(function*() { const throttleChannel = yield actionChannel(pattern) while (true) { const action = yield take(throttleChannel) yield fork(task, ...args, action) yield delay(ms) } })
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]