开发文档
- https://redux-saga.js.org/
- https://redux-saga-in-chinese.js.org/
- https://redux-actions.js.org/
源码
代码已经上传到github中,欢迎star或者fork
redux-saga
一、介绍
之前异步处理用的是redux-thunk + redux-actions + redux-promise,但是随着ES6中Generator的出现,人们发现用Generator处理异步可以更简单。而redux-saga就是用Generator来处理异步。
redux-saga文档并没有说自己是处理异步的工具,而是说用来处理边际效应(side effects),这里的边际效应你可以理解为程序对外部的操作,比如请求后端,比如操作文件。
redux-saga同样是一个redux中间件,它的定位就是通过集中控制action,起到一个类似于MVC中控制器的效果。
同时它的语法使得复杂异步操作不会像promise那样出现很多then的情况,更容易进行各类测试。
二、 安装
npm install --save redux-saga
三、saga常用辅助函数
put、call、takeEvery、takeLatest
1、put和call
put相当于redux的dispatch的作用,而call相当于调用函数
export function* delayChangeBtnText() { yield delay(1000); yield put(changeBtnText('123')); yield call(consoleMsg, '完成改变'); }
2、takeEvery
它提供了类似 redux-thunk 的行为
import { takeEvery } from 'redux-saga' function* watchFetchData() { yield* takeEvery('FETCH_REQUESTED', fetchData) }
3、takeLatest
takeEvery 允许多个 fetchData 实例同时启动。在某个特定时刻,尽管之前还有一个或多个 fetchData 尚未结束,我们还是可以启动一个新的 fetchData 任务,
如果我们只想得到最新那个请求的响应(例如,始终显示最新版本的数据)。我们可以使用 takeLatest辅助函数
import { takeLatest } from 'redux-saga' function* watchFetchData() { yield* takeLatest('FETCH_REQUESTED', fetchData) }
四、使用
1、修改store/index.js
import { createStore, applyMiddleware } from 'redux'; // import thunk from 'redux-thunk'; import createSagaMiddleware from 'redux-saga'; import {watchAppSearch} from './sagas'; import rootReducer from './reducers'; /** * saga用法 * 1.创建一个 Saga middleware * 2.使用 applyMiddleware 将 middleware 连接至 Store * 3.使用 sagaMiddleware.run(helloSaga) 运行 Saga */ const sagaMiddleware = createSagaMiddleware(); // 创建store的时候,第二个参数是中间件,redux-thunk提供了一个thunk中间件,用于处理异步的action let store = createStore( rootReducer, applyMiddleware(sagaMiddleware) ); // 运行并监控各个action sagaMiddleware.run(watchAppSearch); export default store
2、创建store/sagas.js
import { put, call, takeEvery,takeLatest } from 'redux-saga/effects'; import { actionCreators } from './action' import $api from '../api/index.js'; /** * 处理编辑效应的函数 */ export function* appSearch(action) { // 在saga中这里通过action.payload获取到前台传过来的keyword内容 const p = function(){ return $api.lookUp({ keyword:action.payload }) .then(res => res.results) .then(res =>{ return res }) } const res = yield call(p); // 执行p函数,返回值赋值给res yield put(actionCreators.saveSearchList(res));// 通过put触发dispatch ,将返回数据传过去 } /** * 监控Action的函数 */ // takeLatest 和 takeEvery 不同,在任何时刻 takeLatest 只允许一个 fetchData 任务在执行。 // 并且这个任务是最后被启动的那个。 如果已经有一个任务在执行的时候启动另一个 fetchData ,那之前的这个任务会被自动取消。 export function* watchAppSearch() { yield takeEvery(actionCreators.appSearch, appSearch); }
3、同时启动多个Sagas 监听action动作
// 同时启动多个Sagas 监听action动作 export default function* rootSaga() { yield all([ takeLatest(actionCreators.appSearch, appSearch), takeLatest(actionCreators.getRecommendList, getRecommendList) ]) } /** * app搜索获取结果列表 */ export function* appSearch(action) { // 在saga中这里通过action.payload获取到前台传过来的keyword内容 const p = function(){ return $api.lookUp({ keyword:action.payload }) .then(res => res.results) .then(res =>{ return res }) } const res = yield call(p); // 执行p函数,返回值赋值给res yield put(actionCreators.saveSearchList(res));// 通过put触发dispatch ,将返回数据传过去 } /** * 请求获取推荐列表 * @param {*} action */ export function* getRecommendList(action) { const p = function(){ return $api.recommendData({}) .then(res => res.feed) .then(res =>{ return res }) } const res = yield call(p); // 执行p函数,返回值赋值给res yield put(actionCreators.getRecommendListSucceeded(res.entry)); }
redux-actions
redux-actions用来简化redux重复代码,这部分简化工作主要集中在构造action和处理reducers方面。
一、安装
npm install --save redux-actions
二、使用
-----action.js
import * as types from './action-types' import { createActions } from 'redux-actions'; /** * 使用redux-actions之前 */ // export const saveSearchList = (searchList) => { // console.log('searchList',searchList) // return { // type: types.SAVE_SERACH_LIST, // searchList // } // } // export const removeSearchList = () => { // return { // type: types.REMOVE_SERACH_LIST // } // } /** * 使用redux-actions之后 */ // 使用createAction创建单个动作 // export const saveSearchList = createAction(types.SAVE_SERACH_LIST,searchList=>searchList); // export const removeSearchList = createAction(types.REMOVE_SERACH_LIST); // 使用createActions创建多个动作 export const actionCreators = createActions({ [types.SAVE_SEARCH_LIST]:searchList=>searchList, [types.REMOVE_SEARCH_LIST]:()=>null });
-----reducer.js
import * as types from './action-types' import { handleActions } from 'redux-actions'; let defaultState = { searchList: []//搜索结果列表 } /** * 使用redux-actions之前 */ // 修改state // export default(state = defaultState, action={})=>{ // switch (action.type) { // case types.SAVE_SERACH_LIST: // return { // ...state, // searchList: action.searchList // } // case types.REMOVE_SERACH_LIST: // return{ // ...state, // searchList:[] // } // default: // return state // } // } /** * 使用redux-actions之后 */ // handleAction单个action处理 // const reducer = handleAction(types.SAVE_SERACH_LIST,(state, action)=>{ // return { // ...state, // searchList: action.searchList // } // },defaultState); // 使用handleActions处理多个actions ,这里需要注意的是 通过action.payload获取传过来的数据 const reducerCreators = handleActions({ [types.SAVE_SEARCH_LIST]:(state, action)=>{ return { ...state, searchList: action.payload } }, [types.REMOVE_SEARCH_LIST]:(state, action)=>{ return{ ...state,st searchList:[] } } },defaultState); export default reducerCreators;
---index.js
import React, { Component } from 'react'; import { connect } from 'react-redux'; import { actionCreators } from '../../store/action' /** * 使用redux-action之前 */ // const mapDispatchToProps = (dispatch) => ({ // 分发由action creators创建的actions // saveSearchList: searchList => dispatch(saveSearchList(searchList)), // removeSearchList: () => dispatch(removeSearchList()) // }) /** * 使用redux-action之后 */ // createActions会返回一个对象,对象针对每个action类型都有一个值为action工厂的属性,属性名为action类型的值去掉下划线后的驼峰命名 const mapDispatchToProps = { saveSearchList:actionCreators.saveSearchList, removeSearchList:actionCreators.removeSearchList } // 通过connect生成容器组件 export default connect(mapStateToProps,mapDispatchToProps)(SearchResult);
源码
代码已经上传到github中,欢迎star或者fork
参考阅读
- https://juejin.im/post/5b41641ef265da0f8202126d
- https://www.jianshu.com/p/d2615a7d725e
- https://segmentfault.com/a/1190000017064759?utm_source=tag-newest