index.js:

    1. import { channel } from './channel'
    2. //promise判断
    3. const isPromise = p => {
    4. return typeof p.then == 'function' && typeof p.catch == 'function'
    5. }
    6. function createSagaMiddelware() {
    7. function sagaMiddelware({getState,dispatch}){
    8. //负责把gernerator执行完毕
    9. function run(iterator){
    10. //执行得到迭代器,next得到值,可能是器也可能是迭代器
    11. let it = typeof iterator == 'function'?iterator():iterator;
    12. function next(input){
    13. let {value: effect,done}=it.next(input);
    14. //如果迭代器没有完成
    15. if(!done){
    16. //genrator
    17. if(typeof effect[Symbol.iterator] == 'function'){
    18. run(effect);
    19. next();
    20. }
    21. //延迟函数
    22. if(isPromise(effect)) {
    23. effect
    24. .then(next)
    25. .catch(error => next(error))
    26. }
    27. switch(effect.type){
    28. //注册事件
    29. case 'take':
    30. let {actionType}=effect;
    31. channel.subscribe(actionType,next);
    32. break;
    33. //走到put的事件就直接dispatch执行了
    34. case 'put':
    35. let {action}=effect;
    36. dispatch(action);
    37. next(action);
    38. break;
    39. //fork继续执行
    40. case 'fork':
    41. let {worker}=effect;
    42. run(worker);
    43. next();
    44. break;
    45. //异步执行成功后再next
    46. case 'call':
    47. let {fn,args}=effect;
    48. fn(...args).then(next);
    49. break;
    50. default:
    51. break;
    52. }
    53. }
    54. }
    55. next()
    56. }
    57. sagaMiddelware.run = run;
    58. //中间件执行
    59. return (next) => (action) => {
    60. next(action)
    61. channel.publish(action)
    62. }
    63. }
    64. return sagaMiddelware;
    65. }
    66. export default createSagaMiddelware;

    channel.js

    1. function createChannel() {
    2. //对象每一个动作对应一个回调函数
    3. let takers={};
    4. function subscribe(actionType,cb) {
    5. takers[actionType]=cb;
    6. }
    7. function publish(action) {
    8. //监听
    9. let taker=takers[action.type]
    10. if (taker) {//如果有执行监听函数并且删除监听函数
    11. let tmp=taker;
    12. taker = null;
    13. tmp(action);
    14. }
    15. }
    16. return {subscribe,publish};
    17. }
    18. export let channel = createChannel();

    effect.js

    1. function take(actionType) {
    2. return {
    3. type: 'take',
    4. actionType
    5. }
    6. }
    7. function put(action) {
    8. return {
    9. type: 'put',
    10. action
    11. }
    12. }
    13. function fork(worker) {
    14. return {
    15. type: 'fork',
    16. worker
    17. }
    18. }
    19. function call(fn,...args) {
    20. return {
    21. type: 'call',
    22. fn,
    23. args
    24. }
    25. }
    26. //监听每一个动作类型,当此动作发生的时候执行对应的worker
    27. //takeEvery它会单开一个任务,并不会阻塞当前saga
    28. function* takeEvery(actionType,worker) {
    29. yield fork(function* () {
    30. while (true) {
    31. let action = yield take(actionType);
    32. yield worker(action);
    33. }
    34. })
    35. }
    36. function delay(ms, val = true) {
    37. let timeoutId
    38. const promise = new Promise(resolve => {
    39. timeoutId = setTimeout(() => resolve(val), ms)
    40. })
    41. promise['CANCEL_PROMISE'] = () => clearTimeout(timeoutId)
    42. return promise
    43. }
    44. //takerEvery的结果是一个迭代器
    45. //iterator
    46. export {
    47. take,
    48. put,
    49. takeEvery,
    50. call,
    51. delay
    52. }

    使用:
    app.js:

    1. import React from 'react';
    2. import ReactDOM from 'react-dom';
    3. import Root from './router';
    4. import {createStore, applyMiddleware } from 'redux';
    5. import { Provider } from 'react-redux';
    6. import createSagaMiddleware from './testSaga/index.js'
    7. // import createSagaMiddleware from './saga/index'
    8. import { watchIncrementAsync, watchAndLog } from './sagaActions/index'
    9. //globe css
    10. import './style/index.styl';
    11. import './style/less.less';
    12. import './style/sass.sass';
    13. import './style/scss.scss';
    14. const initialState = {
    15. number: 0,
    16. list: []
    17. };
    18. const incrementReducer = (state = initialState, action) => {
    19. switch(action.type) {
    20. case 'INCREMENT': {
    21. state.number += 1
    22. return { ...state }
    23. break
    24. }
    25. case 'DECREMENT': {
    26. return {
    27. ...state,
    28. list: action.data.data
    29. }
    30. break
    31. };
    32. default: return state;
    33. }
    34. };
    35. const sagaMiddleware = createSagaMiddleware();
    36. const store = createStore(incrementReducer,applyMiddleware(sagaMiddleware))
    37. sagaMiddleware.run(watchIncrementAsync)
    38. // sagaMiddleware.run(watchAndLog)
    39. ReactDOM.render(
    40. <Provider store={store}>
    41. <Root />
    42. </Provider>,
    43. document.getElementById('app')
    44. );

    sagaAction:

    1. // import { delay } from '../saga'
    2. // import { select, call, fork, take, put, takeEvery } from '../saga/effects'
    3. import { call, put, takeEvery, take, delay } from '../testSaga/effect'
    4. import {GetUserData} from '../fetch/api.js'
    5. export function* watchAndLog() {
    6. while (true) {
    7. const action = yield take('*')
    8. const state = yield select()
    9. console.log('action', action)
    10. console.log('state after', state)
    11. }
    12. }
    13. export function* incrementAsync() {
    14. yield delay(1000)
    15. yield put({ type: 'INCREMENT' })
    16. }
    17. export function* indecrementAsyncs({ payload }) {
    18. //发起请求 payload是给请求函数的参数
    19. const data = yield call(GetUserData, payload);
    20. yield put({ type: 'DECREMENT', data })
    21. }
    22. //发起请求
    23. function* fetchUrl(param) {
    24. const data = yield call(GetUserData, param); // 指示中间件调用 fetch 异步任务
    25. yield put({ type: 'DECREMENT', data }); // 指示中间件发起一个 action 到 Store
    26. }
    27. export function* watchIncrementAsync() {
    28. yield takeEvery('INCREMENT_ASYNC', incrementAsync)
    29. yield takeEvery('DECREMENT_ASYNC', indecrementAsyncs)
    30. //或者
    31. // while(true) {
    32. // const action = yield take('FETCH_REQUEST'); // 指示中间件等待 Store 上指定的 action,即监听 action
    33. // yield fork(fetchUrl, action.payload); // 指示中间件以无阻塞调用方式执行 fetchUrl
    34. // }
    35. }

    发起事件:

    1. onClick() {
    2. this.props.dispatch({
    3. type: 'DECREMENT_ASYNC',
    4. // type: 'FETCH_REQUEST',
    5. //参数的传递
    6. payload: {
    7. name: 'test',
    8. s:11
    9. }
    10. })
    11. }