25. Redux-saga中间件

Redux-saga中间件

Redux-saga和Redux-thunk一样,都是异步处理的中间件。

安装

1
cnpm install redux-saga

使用saga

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import { createStore, applyMiddleware, compose } from 'redux'
import reducer from './reducer'

// 载入sage组件和自定义的sagas文件
import createSagaMiddleware from 'redux-saga'
import todoSagas from './sagas'

// 创建sage中间件
const sagaMiddleware = createSagaMiddleware()
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware),);
const store = createStore(
reducer,
enhancer
);

// sagaMiddleware运行saga
sagaMiddleware.run(todoSagas)
export default store;


// import { createStore, applyMiddleware, compose } from 'redux'
// import reducer from './reducer'
// import thunk from 'redux-thunk';

// const sagaMiddleware = createSagaMiddleware()
// const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
// const enhancer = composeEnhancers(applyMiddleware(thunk),);
// const store = createStore(
// reducer,
// enhancer
// );

// export default store;

定义异步发起action

容器组件TodoList中

1
2
3
4
componentDidMount(){
const action = getInitListData()
store.dispatch(action)
}

actionCreator中

1
2
3
export const getInitListData = () => ({
type: GTE_INIT_LIST_DATA, // GTE_INIT_LIST_DATA在reducer中不存在
})

actionTypes中

1
export const GTE_INIT_LIST_DATA = 'get_init_list_data'

saga处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import { put, takeEvery } from 'redux-saga/effects'
import { initListDataAction } from './actionCreator'
import axios from 'axios'
import { GTE_INIT_LIST_DATA } from './actionTypes'

function* getInitListDataApi(){
try{
const url = 'http://www.mocky.io/v2/5ba88d043200005f00e2eafb'
// 直到获取到数据后才继续往下执行
const res = yield axios.get(url)
// 重新定义一个新的action来处理接收到数据
const action = initListDataAction(res.data)
// 这里不执行dispatch,执行put将action提交给reducer
yield put(action)

}catch(e){
console.log('接口请求失败')
}
}


function* todoSagas() {
// 除了reducer能接受action之外,saga也可以接收action,下面的代码表示的是,
// 当接收到GTE_INIT_LIST_DATA的action的时候,就执行getInitListDataApi函数
// getInitListDataApi 可以是一个函数,也可以是一个生成器
yield takeEvery(GTE_INIT_LIST_DATA, getInitListDataApi)
}

export default todoSagas;

// 个人理解的sage流程:
/*
1. 编写action
2. dispatch触发后,saga进行拦截
3. 如果在saga的拦截范围内,则进行对应的函数,并且之后将新的action对象put到reducer中
4. 如果不在saga的拦截范围内,那么就直接放行给reducer
*/

// saga和thunk的对比
/*
saga比thunk复杂很多,thunk的原理是将action的返回格式从js对象拓展为js的函数,从而在函数中进行逻辑处理和异步请求等。
而saga是发送给reducer的action进行拦截处理
*/

actionCreator中

1
2
3
4
export const initListDataAction = (value) => ({
type: INIT_LIST_DATA,
value
})

actionTypes中

1
export const INIT_LIST_DATA = 'init_list_data'

reducer中

1
2
3
4
5
if (action.type === INIT_LIST_DATA){
const newState = JSON.parse(JSON.stringify(state));
newState.list = action.value
return newState;
}

https://github.com/rexyan/simple_react/tree/Redux-saga%E4%B8%AD%E9%97%B4%E4%BB%B6