saga分類react
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);
}
複製代碼
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
}
複製代碼