关于redux-saga:redusaga的基本使用及相关原理

redux-saga是什么?家喻户晓, redux-saga 是一个中间件。所谓的中间件就是给redux提供额定性能的, 简而言之 , 也就是对redux中的dispatch, 加上一些性能, 进行包装。 咱们为什么要应用redux-saga呢?在redux中, 如果咱们dispatch一个action之后 , 会调用reducer函数 。 function dispatch(action) { state = reducer(state, action); listeners.forEach(l => l()); return action; }而后reducer是一个纯函数, 没有副作用 ,当咱们须要进行异步申请的时候,这个时候redux就不够用了 , 因而咱们须要借助于redux-saga。 redux-saga如何进行裁减redux的性能呢?中间件的根本格局咱们在裁减中间件的时候会应用一个applyMiddleware的函数, 对原有的store.dispatch进行裁减。 function applyMiddleare(...middlewares) { return function (createStore) { return function (reducer, preloadedState) { let store = createStore(reducer, preloadedState); let dispatch; let middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action), }; let chain = middlewares.map((middleware) => middleware(middlewareAPI)); dispatch = compose(...chain)(store.dispatch); return { ...store, dispatch, }; }; };}//compose函数是:function compose(funcs){return funcs.map((a, b) => (...args) => a(b(...args)))}由上面这段代码能够看出一个中间件, 是承受一个middleAPI也就是store,以及上一次革新后的dispatch, 而后返回一个新的革新后的dispatch。 ...

August 17, 2022 · 3 min · jiezi

简化Reduxsaga

想一下,如果你需要写一个基于Redux 的项目,你需要重复的写非常多的Action Constants,非常多的Action Creator以做相当大一部分差不多相同的事情。 于是出现了为了帮你减少书写重复Constants及Action Creator 的库redux-act。 但只有Redux并不能完全满足我们的业务需求,毕竟SPA项目中总是需要从服务端获取数据的,于是这时候我们整合进来Redux-saga。 Redux-saga能非常好的帮助我们处理异步事件,但是同样的,Redux-saga需要书写许多的Action Creator并指定其Take类型再合并到Redux-Saga的入口处,而且这些Action Creator及effect非但需要一一让参数对应,还不方便做统一的事件处理。 于是Saga-action-creator诞生了。 Saga-action-creator的特性减少重复繁琐的书写Action creator直观的参数传递支持插件保留了Redux-saga的所有特性优秀的Typescript支持更方便的测试如何使用使用Saga-action-creator的方法非常简单,只需3步 一、定义Saga effects并导出import createSagaActions from 'saga-action-creator';import { takeLatest, call } from 'redux-saga/effects';import { getUserInfo, updateUser } from '../services/user';const user = createSagaActions({ // 一般情况下,你可以直接写一个Effect *getUserById(id: string): Generator<any, any, any> { yield call(getUserInfo, id); }, // 当然,如果你需要为某一个Effect指定take的类型 // 你可以传递一个对象,并指定takeType属性 updateUser: { takeType: takeLatest, *effect(id: string, name: string): Generator<any, any, any> { yield call(updateUser, id, { name }); }, },});export default user;二、创建连接器并合并Creatorsimport { createConnection, getLoadingPlugin } from 'saga-action-creator';import user from './user';import { takeLatest } from 'redux-saga/effects';const creator = createConnection({ // 合并creator creators: { user, }, // 默认情况下effect的take类型为 `takeEvery` // 如果你需要修改默认的类型可以传递这个参数 defaultTakeType: takeLatest, // 添加插件 plugins: { // 这里插件的key将作为后面getReducers的导出的key,则为store名 loading: getLoadingPlugin(), },});export default creator;三、将插件与Redux及Redux-saga进行连接import { createStore, combineReducers, applyMiddleware } from 'redux';import { all } from 'redux-saga/effects';import createSagaMiddleware from 'redux-saga';import creator from '../sagas';// 将插件导出的reducers与store连接const reducers = combineReducers({ ...creator.getReducers(),});const sagaMiddleware = createSagaMiddleware();// 将Effects与Redux-saga连接sagaMiddleware.run(function*() { yield all(creator.getEffects());});const store = createStore(reducers, applyMiddleware(sagaMiddleware));export type AppState = ReturnType<typeof reducers>;export default store;至此,saga-action-creator的连接动作就全部做完了。 ...

October 14, 2019 · 2 min · jiezi

React项目集成Immutablejs

1、前言本文章项目的依赖包及其版本如下: Package NameVersionantd^3.16.6connected-react-router^6.4.0customize-cra^0.2.12immutable^4.0.0-rc.12react^16.8.6react-app-rewired^2.1.1react-redux^7.0.3react-router-config^5.0.0react-router-dom^5.0.0react-scripts3.0.1redux^4.0.1redux-logger^3.0.6redux-persist^5.10.0redux-persist-expire^1.0.2redux-persist-transform-immutable^5.0.0redux-saga^1.0.22、准备工作,搭建项目下面是我的项目结构,每个人或者每个公司都有自己的目录架构,这里我的只供大家参考,另外搭建项目过程和介绍如何使用immutable.js不是本文章的重点,如何使用immutable.js以及本文章相关代码后面我会给出,如果有疑问欢迎大家在下面留言 |-- App.js|-- index.js|-- serviceWorker.js|-- assets| |-- audio| |-- css| | |-- App.scss| | |-- base.scss| | |-- index.css| | |-- override-antd.scss| |-- image| | |-- Welcome.png| | |-- awbeci.png| | |-- bgLogo.png| | |-- hiy_logo.png| | |-- indexPop1.png| | |-- indexPop2.png| | |-- logo.png| | |-- logoX.png| | |-- right.png| |-- video|-- components| |-- HOC| | |-- loading.js| |-- common| |-- layout| |-- AppRoute.js| |-- LayoutPage.js| |-- Loading.js| |-- MasterPage.js| |-- RouterView.js| |-- SideMenu.js| |-- layoutPage.scss| |-- masterPage.scss|-- config| |-- base.conf.js|-- context| |-- themeContext.js|-- pages| |-- DepartmentManage.js| |-- Index.js| |-- NoFound.js| |-- NoPermission.js| |-- UserManage.js| |-- login| |-- Login.js| |-- login.scss|-- redux| |-- actions| | |-- authAction.js| | |-- layoutPageAction.js| |-- middleware| | |-- authTokenMiddleware.js| |-- reducers| | |-- authReducer.js| | |-- index.js| | |-- layoutPageReducer.js| |-- sagas| | |-- authSaga.js| | |-- index.js| |-- store| | |-- index.js| |-- thunks|-- router| |-- index.js|-- service| |-- apis| | |-- 1.0| | |-- index.js| | |-- urls.js| |-- mocks| | |-- 1.0| | |-- index.js| | |-- testMock.js| |-- request| |-- ApiRequest.js| |-- MockRequest.js|-- test| |-- App.test.js|-- utils3、集成immutable.js此项目除了依赖包要配置之外,只有redux下的reducer相关文件会设置成immutable.js普通的react组件我没有设置成immutable.js ...

June 1, 2019 · 4 min · jiezi

redux中间件的使用

redux-thunk功能: 使用中间件可以在action中返回函数,可以用来处理ajax异步请求使用方法index.js import { createStore, applyMiddleware, compose } from ‘redux’; import reducer from ‘./reducer’; import thunk from ‘redux-thunk’; // 解决 redux-devtools-extension 使用问题 const composeEnhancers = window.REDUX_DEVTOOLS_EXTENSION_COMPOSE ? window.REDUX_DEVTOOLS_EXTENSION_COMPOSE({}) : compose; const enhancer = composeEnhancers( applyMiddleware(thunk) ); const store = createStore(reducer, enhancer);actionCreators.js import { INIT_LIST_ACTION } from ‘./actionTypes’; import axios from ‘axios’; export const initListAction = (data) => ({ type: INIT_LIST_ACTION, data }); export const getTodoList = () => { return (dispatch) => { axios.get(’/api/…’).then(res => { const data = res.data; const action = initListAction(data); dispatch(action); }) }; };reducer.js import { INIT_LIST_ACTION } from ‘./actionTypes’; const defaultState = { inputValue: “”, list: [] }; export default (state = defaultState, action) => { if(action.type === INIT_LIST_ACTION) { const newState = JSON.parse(JSON.stringify(state)); newState.list = action.data; return newState; } return state; }actionTypes.js export const INIT_LIST_ACTION = ‘init_list_action’;参考: redux-thunkredux-saga功能: 处理react异步请求数据,适用于大型项目使用方法index.js import { createStore, applyMiddleware, compose } from ‘redux’; import reducer from ‘./reducer’; import createSagaMiddleware from ‘redux-saga’; import todoSaga from ‘./sagas’; 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.run(todoSaga);reducer.js import { INIT_LIST_ACTION } from ‘./actionTypes’; const defaultState = { inputValue: “”, list: [] }; export default (state = defaultState, action) => { if(action.type === INIT_LIST_ACTION) { const newState = JSON.parse(JSON.stringify(state)); newState.list = action.data; return newState; } return state; }sagas.js // takeEvery 在每个 GET_TODO_LIST action 被 dispatch 时调用 getTodoList // 允许并发(译注:即同时处理多个相同的 action) // put 相当于store中的dispatch方法,派发action import { takeEvery, put } from ‘redux-saga/effects’; import { GET_TODO_LIST } from ‘./actionTypes’; import { initListAction } from ‘./actionCreators’; import axios from ‘axios’; function* getTodoList() { try { const res = yield axios.get(’/list.json’); const action = initListAction(res.data); yield put(action); }catch (e) { console.log(“list.json 网络超时”); } } function* mySaga() { yield takeEvery(GET_TODO_LIST, getTodoList); } export default mySaga;actionCreators.js import { GET_TODO_LIST } from ‘./actionTypes’; export const getTodoList = () => ({ type: GET_TODO_LIST });actionTypes.js export const INIT_LIST_ACTION = ‘init_list_action’; export const GET_TODO_LIST = ‘get_todo_list’;参考: redux-saga ...

April 4, 2019 · 2 min · jiezi