index.js:
import { channel } from './channel'
//promise判断
const isPromise = p => {
return typeof p.then == 'function' && typeof p.catch == 'function'
}
function createSagaMiddelware() {
function sagaMiddelware({getState,dispatch}){
//负责把gernerator执行完毕
function run(iterator){
//执行得到迭代器,next得到值,可能是器也可能是迭代器
let it = typeof iterator == 'function'?iterator():iterator;
function next(input){
let {value: effect,done}=it.next(input);
//如果迭代器没有完成
if(!done){
//genrator
if(typeof effect[Symbol.iterator] == 'function'){
run(effect);
next();
}
//延迟函数
if(isPromise(effect)) {
effect
.then(next)
.catch(error => next(error))
}
switch(effect.type){
//注册事件
case 'take':
let {actionType}=effect;
channel.subscribe(actionType,next);
break;
//走到put的事件就直接dispatch执行了
case 'put':
let {action}=effect;
dispatch(action);
next(action);
break;
//fork继续执行
case 'fork':
let {worker}=effect;
run(worker);
next();
break;
//异步执行成功后再next
case 'call':
let {fn,args}=effect;
fn(...args).then(next);
break;
default:
break;
}
}
}
next()
}
sagaMiddelware.run = run;
//中间件执行
return (next) => (action) => {
next(action)
channel.publish(action)
}
}
return sagaMiddelware;
}
export default createSagaMiddelware;
channel.js
function createChannel() {
//对象每一个动作对应一个回调函数
let takers={};
function subscribe(actionType,cb) {
takers[actionType]=cb;
}
function publish(action) {
//监听
let taker=takers[action.type]
if (taker) {//如果有执行监听函数并且删除监听函数
let tmp=taker;
taker = null;
tmp(action);
}
}
return {subscribe,publish};
}
export let channel = createChannel();
effect.js
function take(actionType) {
return {
type: 'take',
actionType
}
}
function put(action) {
return {
type: 'put',
action
}
}
function fork(worker) {
return {
type: 'fork',
worker
}
}
function call(fn,...args) {
return {
type: 'call',
fn,
args
}
}
//监听每一个动作类型,当此动作发生的时候执行对应的worker
//takeEvery它会单开一个任务,并不会阻塞当前saga
function* takeEvery(actionType,worker) {
yield fork(function* () {
while (true) {
let action = yield take(actionType);
yield worker(action);
}
})
}
function delay(ms, val = true) {
let timeoutId
const promise = new Promise(resolve => {
timeoutId = setTimeout(() => resolve(val), ms)
})
promise['CANCEL_PROMISE'] = () => clearTimeout(timeoutId)
return promise
}
//takerEvery的结果是一个迭代器
//iterator
export {
take,
put,
takeEvery,
call,
delay
}
使用:
app.js:
import React from 'react';
import ReactDOM from 'react-dom';
import Root from './router';
import {createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import createSagaMiddleware from './testSaga/index.js'
// import createSagaMiddleware from './saga/index'
import { watchIncrementAsync, watchAndLog } from './sagaActions/index'
//globe css
import './style/index.styl';
import './style/less.less';
import './style/sass.sass';
import './style/scss.scss';
const initialState = {
number: 0,
list: []
};
const incrementReducer = (state = initialState, action) => {
switch(action.type) {
case 'INCREMENT': {
state.number += 1
return { ...state }
break
}
case 'DECREMENT': {
return {
...state,
list: action.data.data
}
break
};
default: return state;
}
};
const sagaMiddleware = createSagaMiddleware();
const store = createStore(incrementReducer,applyMiddleware(sagaMiddleware))
sagaMiddleware.run(watchIncrementAsync)
// sagaMiddleware.run(watchAndLog)
ReactDOM.render(
<Provider store={store}>
<Root />
</Provider>,
document.getElementById('app')
);
sagaAction:
// import { delay } from '../saga'
// import { select, call, fork, take, put, takeEvery } from '../saga/effects'
import { call, put, takeEvery, take, delay } from '../testSaga/effect'
import {GetUserData} from '../fetch/api.js'
export function* watchAndLog() {
while (true) {
const action = yield take('*')
const state = yield select()
console.log('action', action)
console.log('state after', state)
}
}
export function* incrementAsync() {
yield delay(1000)
yield put({ type: 'INCREMENT' })
}
export function* indecrementAsyncs({ payload }) {
//发起请求 payload是给请求函数的参数
const data = yield call(GetUserData, payload);
yield put({ type: 'DECREMENT', data })
}
//发起请求
function* fetchUrl(param) {
const data = yield call(GetUserData, param); // 指示中间件调用 fetch 异步任务
yield put({ type: 'DECREMENT', data }); // 指示中间件发起一个 action 到 Store
}
export function* watchIncrementAsync() {
yield takeEvery('INCREMENT_ASYNC', incrementAsync)
yield takeEvery('DECREMENT_ASYNC', indecrementAsyncs)
//或者
// while(true) {
// const action = yield take('FETCH_REQUEST'); // 指示中间件等待 Store 上指定的 action,即监听 action
// yield fork(fetchUrl, action.payload); // 指示中间件以无阻塞调用方式执行 fetchUrl
// }
}
发起事件:
onClick() {
this.props.dispatch({
type: 'DECREMENT_ASYNC',
// type: 'FETCH_REQUEST',
//参数的传递
payload: {
name: 'test',
s:11
}
})
}