什么是中间件
中间件本质是就是一道函数,redux允许我们通过中间件的方式扩展和增强redux的应用,体现在action的处理逻辑上,
加载中间件之后,action会先被中间件处理,中间件在返回给reducer
源码地址:https://github.com/qifutian/learngit/tree/main/redux%E5%8F%8A%E4%B8%AD%E9%97%B4%E4%BB%B6/react-redux-guide
redux的中间件本质是一道函数,并且是函数柯里化的函数
开发中间件的模板代码
export default store => next => action => {
}
store是传过来的store仓库
next是函数的参数,也是一个函数,当中间件逻辑完成后,会调用next,目的是把当前action传给reducer,或是下一个中间件
注册中间件
中间件在开发完成以后资源被注册才能在redux的流程中生效
import {
createStore,applyMiddleware} from 'redux'
import logger from './middlewares/logger'
createStore(reducer,applyMiddleware(logger))
开发的logger作为参数被redux应用
开发中间件的功能,就是在触发action之后,会将对应的信息打印到控制台中
在已有项目中新建middleware文件夹,新建logger.js
export default function (){
return function(next){
return function(action){
}
}
}
或者ES6方式
export default store => next =>{
console.log(action)
console.log(action)
next(action) // 必须调用next,要不然就传递不了action,reducer也接收不到
}
注册中间件
需要redux中的applyMiddleware方法
import {
createStore, applyMiddleware } from "redux";
import RootReducer from "./reducers/root.reducer";
import logger from "./middleware/logger";
export const store = createStore(RootReducer, applyMiddleware(logger));
在点击事件触发action中,会获取到action
多个中间件只需要在logger后面继续增加就好,调用顺序也是先logger,然后是之后的
新建thunk.js
让对应的事件延迟执行2秒
export default ({
dispatch}) => next => action => {
if (typeof action.type === 'increment') {
setTimeout(()=>{
next(action)
},2000)
}
}
在index.js注册
import {
createStore, applyMiddleware } from "redux";
import RootReducer from "./reducers/root.reducer";
import thunk from './middleware/thunk';
import logger from "./middleware/logger";
export const store = createStore(RootReducer, applyMiddleware(logger,thunk));
export default ({
dispatch}) => next => action => {
// 1. 当前这个中间件函数不关心你想执行什么样的异步操作 只关心你执行的是不是异步操作
// 2. 如果你执行的是异步操作 你在触发action的时候 给我传递一个函数 如果执行的是同步操作 就传递action对象
// 3. 异步操作代码要写在你传递进来的函数中
// 4. 当前这个中间件函数在调用你传递进来的函数时 要将dispatch方法传递过去
if (typeof action === 'function') {
return action(dispatch)
}
next(action)
}
下载 npm insatll redux-thunk
引入
import {
createStore, applyMiddleware } from "redux";
import RootReducer from "./reducers/root.reducer";
import thunk form "redux-thunk"
export const store = createStore(RootReducer, applyMiddleware(thunk));
使用,异步调用
export const increment_async = payload =>dispatch => {
setTimeout(()=>{
dispatch(increment(payload))
},2000)
}
redux-saga解决问题:saga可以将异步操作从Action Creator 文件中抽离出来,放在单独一个文件中
项目代码更好维护
下载 npm install redux-saga
import createSagaMidddleware from 'redux-saga';
// 创建 sagaMiddleware
const sagaMiddleware = createSagaMidddleware();
export const store = createStore(RootReducer, applyMiddleware(sagaMiddleware));
使用saga接收action进行异步操作
import {
takeEvery, put, delay } from 'redux-saga/effects';
import {
increment } from '../actions/counter.actions';
import {
INCREMENT_ASYNC } from '../const/counter.const';
// takeEvery 接收 action
// put 触发 action
function* increment_async_fn (action) {
yield delay(2000);
yield put(increment(action.payload))
}
export default function* counterSaga () {
// 接收action
yield takeEvery(INCREMENT_ASYNC, increment_async_fn)
}
启动saga
import rootSaga from './sagas/root.saga';
// 启动 counterSaga
sagaMiddleware.run(rootSaga)
步骤:
redux-saga的action传参
在组件中处理方法时需要 以函数形式
处理action中,export const increment_async = payload => ({type: INCREMENT_ASYNC, payload});
在counter.saga.js中,takeEvery处理的函数接收action参数,被reducer中接收到
function* increment_async_fn (action) {
yield delay(2000);
yield put(increment(action.payload))
}
在reducer中根据type类型,返回给页面
saga合并
saga可以进行拆分,更有利于维护,用all方法进行合并
import {
all } from 'redux-saga/effects';
import counterSaga from './counter.saga';
import modalSaga from './modal.saga';
export default function* rootSaga () {
yield all([
counterSaga(),
modalSaga()
])
}
redux-actions解决的问题: redux流程中大量的样板读写很痛苦,使用redux-actions可以简化Action和Reducer的处理
下载 : npm install redux-actions
使用
创建Action
import {
createAction} from 'redux-actions'
const increment_action = createAction("increment")
创建Reducer
import {
handleActions as createReducer } from 'redux-actions'
import {
increment_action,decrement_action } from '../actions/counter.action'
const initialState = {
count:0}
const counterReducer = createReducer({
[increment_action]:(state,action) =>({
count:state.count + 1})
},initialState)
export default counterReducer