redux-saga工做原理

  • sages 採用 Generator 函數來 yield Effects(包含指令的文本對象)
  • Generator 函數的做用是能夠暫停執行,再次執行的時候從上次暫停的地方繼續執行
  • Effect 是一個簡單的對象,該對象包含了一些給 middleware 解釋執行的信息。
  • 你能夠經過使用 effects API 如 fork,call,take,put,cancel 等來建立 Effect。

saga分類react

  1. worker saga 作左右的工做,如調用API,進行異步請求,獲取異步封裝結果
  2. watcher saga 監聽被dispatch的actions,當接受到action或者知道其被觸發時
  3. 調用worker執行任務 root saga 當即啓動saga的惟一入口

saga 組成

  • take 等待一個動做發生,只發生一次redux

  • put 派發一個動做app

  • takeEvery 監聽每一個動做異步

  • call 執行一個動做函數

  • index.js 導出createSagaMiddeware函數,這個函數執行完返回一箇中間件ui

  • effectthis

綜上所述咱們先有個rootSaga做爲惟一入口spa

src/sagas.jscode

// import {takeEvery,put,all,call} from 'redux-saga/effects';
// import * as types from './store/action-types';
// const delay=ms => new Promise(function(resolve,reject){
// setTimeout(function(){
// resolve()
// },ms)
// })
// function* add(dispatch,action,all){
// // setTimeout(function(){
// // dispatch({type:types.ADD})
// // },1000)
// 幫我執行這個動做
// yield call(delay,5000)
// 幫我派發這個動做
// yield put({type:types.ADD})
// }
// function* logger(action){
// console.log(action);
    
// }
// function* watchLogger(){
// yield takeEvery('*',logger)
// }
// function* watchAdd(){
// yield takeEvery(types.ADD_ASYNC,add)
// }
// export function* rootSaga({getState,dispatch}){
// yield all([watchAdd(),watchLogger()]) ;
// }
// import {take,takeEvery,put,all,call} from 'redux-saga/effects';
import {takeEvery,take,put,call} from './redux-saga/effects';
import * as types from './store/action-types';

// export function* rootSaga(){
// // yield {type:'take',acionType:ADD_ASYNC}
// // while(true){
// let action=yield take(types.ADD_ASYNC);
// yield put({type: types.ADD});
// // }
// }
const delay=ms => new Promise(function(resolve,reject){
    setTimeout(function(){
        resolve()
    },ms)
})
function* add(){
    // setTimeout(function(){
    // dispatch({type:types.ADD})
    // },1000)
    yield call(delay,1000)
    yield put({type:types.ADD})
}
export function* rootSaga(){
	let action=yield takeEvery(types.ADD_ASYNC,add);
}
複製代碼

src/components/Counter.jscomponent

import React,{Component} from 'react'
import {connect} from 'react-redux';
import actions from '../store/actions';
class Counter extends Component{
    render() {
        return (
            <div> <p>{this.props.number}</p> <button onClick={this.props.increment}>+</button> </div>
      )
  }
}
export default connect(
    state => state,
    actions
)(Counter);
複製代碼

src/store/index.js

import {createStore, applyMiddleware} from 'redux';
import reducer from './reducer';
import createSagaMiddleware from 'redux-saga';
import {rootSaga} from '../saga';
let sagaMiddleware=createSagaMiddleware();//返回一箇中間件
let store=applyMiddleware(sagaMiddleware)(createStore)(reducer);//應用中間件
sagaMiddleware.run(rootSaga,store);//執行Genrator函數
window.store=store;
export default store;
複製代碼

src/store/actions.js

import * as types from './action-types';
export default {
    increment() {
        return {type:types.INCREMENT}
    }
}
複製代碼

action-types.js #

export const INCREMENT='INCREMENT';
複製代碼

reducer.js

import * as types from './action-types';
export default function (state={number:0},action) {
    switch(action.type){
        case types.INCREMENT:
            return {number: state.number+1};
        default:
            return state;
    }
}
複製代碼

** src/saga.js #**

import {takeEvery,put} from 'redux-saga/effects';
import * as types from './store/action-types';
const delay=ms => new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve();
    },ms);
});
export function* increment(dispatch) {
    yield delay(1000);
    yield put({type:types.INCREMENT});
}

export function* rootSaga({getState,dispatch}) {
    //takeEvery接受每個將停派發給倉庫的動做,每個INCREMENT_ASYNC動做,看成發生的時候,若是對應執行對應的監聽生成器
    yield takeEvery(types.INCREMENT_ASYNC,increment,dispatch);
}
複製代碼

redux-saga實現原理

index.js

function createChannel() {
    //對象每個動做對應一個回調函數
    let takers={};
    function subscribe(actionType,cb) {
        takers[actionType]=cb;
    }
    function publish(action) {//{type:ADD}
        //看看有沒有人監聽
        let taker=takers[action.type]
        if (taker) {//若是有執行監聽函數而且刪除監聽函數
            let tmp=taker;
            delete taker[action.type];
            tmp(action);        
        }
    }
    return {subscribe,publish};
}
let channel=createChannel();   
function createSagaMiddelware() {
    function sagaMiddelware({getState,dispatch}){                
        //負責把gernerator執行完畢 co庫 rootSaga
        function run(iterator){//(rootSaga,store)
            //執行獲得迭代器,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();
                    }else{
        
                    }
                    switch(effect.type){
                        //等待一個動做發生,至關於註冊一個監聽
                        case 'take':
                            let {actionType}=effect;
                            channel.subscribe(actionType,next);
                            break;
                        case 'put':
                            let {action}=effect;
                            dispatch(action);
                            next(action);
                            break;
                        case 'fork':
                            let {worker}=effect;
                            run(worker);
                            next();
                            break;
                        case 'call':
                            let {fn,args}=effect;
                            fn(...args).then(next);
                            break;
                        default:
                            break;
                    }
                }
            }
            next()
        }
        sagaMiddelware.run = run;
        return function(next){
            //下面的是真正的dispatch函數
            return function(action){
                channel.publish(action)
                next(action)
            }  
        }
        
    }
    return sagaMiddelware;
}
export default createSagaMiddelware;
複製代碼

effect.js

//這裏全部的函數都會返回一個effect,effect就是一個普通對象
//effect對象都有一個type屬性
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);
		}
	})
}
//takerEvery的結果是一個迭代器
//iterator
export {
	take,
	put,
	takeEvery,
	call
}
複製代碼
相關文章
相關標籤/搜索