redux-saga
redux的一个中间件,用于实现异步操作
原理
saga是由Generator函数实现的,(Generator函数能够实现将外部数据传入内部,同时将内部函数传递到外部,并能切换调用者,类似于lua中的协程。)我们自己编写Generator函数,Generator函数将会yield包含指令的稳步对象,redux-saga中间件将确保执行这些执行并将指令结果回馈到Generator,实现上述的参数内外互传。例如异步请求,Generator函数yield返回一个Promise对象,当Promise执行resolve后,将成功结果返回到Generator函数内部,继续向下执行。
核心API
recux与saga连接函数
- createSagaMiddleware
用于创建一个redux中间件,将saga于redux的store联系起来,例子见下方。
saga异步action捕捉函数
在同步redux中,当UI通过dispath发出action时,由reducer负责匹配并处理,同理,在saga中,上述两个函数用于捕捉指定action并执行对应的自定义的异步Generator函数
- takeEvery
- takeLast
- take
takeEvery用于捕捉每次action,而takeLast只捕捉并执行最新一次的action
例如:当点击商城某一分类名:单片机 获取对应商品列表时,每点击一次 “单片机”,就像后台获取一次对应分类下的列表。利用saga实现如下:
异步reducer
import { call, put } from "redux-saga/effects"
export function * getData(action){
try{
//像后台发出请求,执行到yield时将执行权移交到saga中间件,知道执行完毕,将结果返回到data中
const data = yield call(Api.getList, action.url);
//拿到结果后,发出aciton,通知UI变化
yield put({type: "GET_SUCCESS",data})
}
}
action捕捉
import { takeEvery } from "redux-saga"
function* watchAsynAction(){
//捕捉每次dispath发出的“GET_GOODS_BY_TYPE”action,捕捉到一次,执行一次getData
yield * takeEvery("GET_GOODS_BY_TYPE",getData)
}
以上两个代码片段一般出现在同一个sagas.js文件中
页面
import {createStore, applyMiddleware } from "redux"
import createSagaMiddleware from "redux-saga"
const sagamiddle = createSagaMiddleware();
const store = createStore({
reducer,//同步reducer
applyMiddleware(sagaMiddleware)
})
class index extends React.Component{
......
render(){
...
<button onClick={store.dispath({type:"GET_GOODS_BY_TYPE"})}>
...
}
...
}
takeLast与takeEvery功能相同,唯一区别是,takeLast只执行最新启动的异步操作,此前如果有未执行的则取消。
take用于监听现在未发生的aciton,阻塞中间件,知道对应action发生,配合fork能够实现类似takeEvery的效果
function* watchAsynAction(){
while(true){
yield take("GET_GOODS_BY_TYPE")
yield fork(getData)
}
}
saga异步调用函数(类似store.dispath方法)
- call (fn, …args)
- fork (fn, …args)
- select (selector, …args)
call和fork都是将fn的调用转移到saga中间件来执行,arg是中间件调用fn函数的参数,两者不同之处在于call是阻塞的,fork是非阻塞的。
saga获取状态函数
- select(selector, …args)
功能类似同步redux中的store.getState,用于获取store中的数据
官方简单例子
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from "redux-saga"
import Counter from './Counter'
import reducer from './reducers'
import rootSaga from "./sagas"
const sagaMiddleware = createSagaMiddleware()
let middlewares = []
middlewares.push(sagaMiddleware)
const store = createStore(
reducer,
applyMiddleware(sagaMiddleware)//createSagaMiddleware 工厂函数来创建一个 Saga middleware。
)
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 { delay, takeEvery } from "redux-saga"
import { put, all, take, fork } from "redux-saga/effects"
export function* helloSaga() {
console.log("hello Sagas");
}
// Our worker Saga :将执行异步的increment 任务
function* incrementAsync() {
//delay是一个promise,延时参数值s后执行resolve,用于block(阻塞)Generator
// Sagas 被实现为 Generator functions,它会 yield 对象到 redux-saga middleware。
//被 yield 的对象都是一类指令,指令可被 middleware 解释执行。当 middleware 取得一个 yield 后的 Promise,
//middleware 会暂停 Saga,直到 Promise 完成。
//在下面的例子中,incrementAsync 这个 Saga 会暂停直到 delay 返回的 Promise 被 resolve,这个 Promise 将在 1 秒后 resolve。
yield delay(1000)
// put 就是我们称作 Effect 的一个例子。
// Effects 是一些简单 Javascript 对象,包含了要被 middleware 执行的指令。
// 当 middleware 拿到一个被 Saga yield 的 Effect,它会暂停 Saga,直到 Effect 执行完成,然后 Saga 会再次被恢复。
yield put({ type: "INCREMENT" })
}
//Our watcher Saga 在每个INCREMENT_ASYNC action spawn 一个新的incrementAsync 任务
function* watchIncrementAsync() {
// yield takeEvery("INCREMENT_ASYNC", incrementAsync);
//与上述 takeEvery 功能相同,疑问:fork何时结束???
while (true) {
yield take('INCREMENT_ASYNC');
yield fork(incrementAsync);
}
}
export default function* rootSaga() {
yield all([
helloSaga(),
watchIncrementAsync()
])
}
reducers.js
export default function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
最后 记录今天复习到的一个词语:陈力就列,不能者止 ,不能适应这个时代,就会被淘汰!