当前位置:网站首页>手写 redux-thunk
手写 redux-thunk
2022-06-29 08:24:00 【CamilleZJ】
了解了redux,还需要好好了解 Redux 相关的生态。
一、redux-thunk
redux-thunk是什么?redux-thunk是redux的中间件, 利用 redux 的中间件可以让 redux 支持异步的 action。
如下:原始的Redux里面,action creator必须返回plain object,而且必须是同步的。
function increment() {
return {
type: 'INCREMENT'
}
};
store.dispatch(increment());如下:涉及到异步操作
function increment() {
return {
type: 'INCREMENT'
}
};
// 异步action creator
function incrementAsync() {
return (dispatch) => {
setTimeout(() => {
dispatch(increment());
}, 1000);
}
}
// 使用了Redux-Thunk后dispatch不仅仅可以发出plain object,还可以发出这个异步的函数
store.dispatch(incrementAsync());
综上可以看出:在使用Redux-Thunk前我们dispatch的action必须是一个纯对象(plain object),使用了Redux-Thunk后,dispatch可以支持函数,这个函数会传入dispatch本身作为参数。
没有 redux-thunk
如果没有 redux-thunk ,异步 action有两种办法如下:
1、先创建「请求数据」的 action,然后再创建一个「更新数据」的 action:

2、直接发请求,得到数据之后创建「更新数据」的 action
setTimeout(() => {
store.dispatch(increment());
}, 1000);如下实现一个简单的通知,5秒后关闭:
store.dispatch({ type: 'SHOW_NOTIFICATION', text: 'You logged in.' })
setTimeout(() => {
store.dispatch({ type: 'HIDE_NOTIFICATION' })
}, 5000)
这样写同样可以在1秒后发出增加的action,而且代码还更简单,那我们为什么还要用Redux-Thunk呢,他存在的意义是什么呢?stackoverflow对这个问题有一个很好的回答,而且是官方推荐的解释。
翻译就是下面的意思:
**不要觉得一个库就应该规定了所有事情!**如果你想用JS处理一个延时任务,直接用
setTimeout就好了,即使你使用了Redux也没啥区别。Redux确实提供了另一种处理异步任务的机制,但是你应该用它来解决你很多重复代码的问题。如果你没有太多重复代码,使用语言原生方案其实是最简单的方案。
具体说明可以看StackOverflow,也可以看翻译后的https://juejin.cn/post/6869950884231675912
redux中间件大概就长这个样子:
- 一个中间件接收
store作为参数,会返回一个函数 - 返回的这个函数接收老的
dispatch函数作为参数(也就是上面的next),会返回一个新的函数 - 返回的新函数就是新的
dispatch函数,这个函数里面可以拿到外面两层传进来的store和老dispatch函数
function logger(store) {
return function(next) {
return function(action) {
console.group(action.type);
console.info('dispatching', action);
let result = next(action);
console.log('next state', store.getState());
console.groupEnd();
return result
}
}
}
redux-thunk 的源码如下:https://github.com/reduxjs/redux-thunk/blob/master/src/index.js

如上,一共就14行代码,在简化以下就如下:
const thunk = ({ dispatch, getState }) => (next) => (action) => {
if (typeof action === 'function') {
return action(dispatch, getState);
}
return next(action);
};
export default thunk
//详细如下:
function thunk(store) {
return function (next) {
return function (action) {
// 从store中解构出dispatch, getState
const { dispatch, getState } = store;
// 如果action是函数,将它拿出来运行,参数就是dispatch和getState
if (typeof action === 'function') {
return action(dispatch, getState);
}
// 否则按照普通action处理
let result = next(action);
return result
}
}
}这段代码的逻辑就是:
- 如果 action 是个函数,就调用这个函数
- 如果 action 不是函数,就传给下一个中间件
其实就是:发现 action 是函数就调用它
有了 redux-thunk:action 就可以是函数了
const action = function(dispatch) {
return fetchUsers().then(
(users) => dispatch({type:'updateUsers', payload: users}),
(error) => dispatch({type:'updateUsersError'}),
);
};
dispatch(action)这个 action 会被调用,然后在将来某个时候创建 updateUsers action,所以我们可以称它为异步 action(其实就是函数),redux-thunk 就是帮你调用这个函数。
源码中:在thunk函数外又包裹了一层,其实就是传递额外的参数
const api = "http://www.example.com/sandwiches/";
const whatever = 42;
const store = createStore(
reducer,
applyMiddleware(thunk.withExtraArgument({ api, whatever })),
);
二、redux-saga
对于复杂场景,Redux-Thunk并不适用,推荐Redux-Saga来处理复杂副作用。Redux-Saga也是在实际工作中使用最多的Redux异步解决方案。Redux-Saga比Redux-Thunk复杂得多,而且他整个异步流程都使用Generator来处理,Generator也是我们这篇文章的前置知识,如果你对Generator还不熟悉,可以看看这篇文章。
redux-saga 是一个 redux 中间件,它具有如下特性:
集中处理 redux 副作用问题。
被实现为 generator 。
类 redux-thunk 中间件。
watch/worker(监听->执行) 的工作形式。
简单案例:点击一个按钮去请求用户的信息,大概长这样

import React from 'react';
import { connect } from 'react-redux';
function App(props) {
const { dispatch, userInfo } = props;
const getUserInfo = () => {
dispatch({ type: 'FETCH_USER_INFO' })
}
return (
<div className="App">
<button onClick={getUserInfo}>Get User Info</button>
<br></br>
{userInfo && JSON.stringify(userInfo)}
</div>
);
}
const matStateToProps = (state) => ({
userInfo: state.userInfo
})
export default connect(matStateToProps)(App);
store.js:
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import reducer from './reducer';
import rootSaga from './saga';
const sagaMiddleware = createSagaMiddleware()
let store = createStore(reducer, applyMiddleware(sagaMiddleware));
// 注意这里,sagaMiddleware作为中间件放入Redux后
// 还需要手动启动他来运行rootSaga
sagaMiddleware.run(rootSaga);
export default store;
saga.js:
import { call, put, takeLatest } from 'redux-saga/effects';
import { fetchUserInfoAPI } from './api';
function* fetchUserInfo() {
try {
const user = yield call(fetchUserInfoAPI);
yield put({ type: "FETCH_USER_SUCCEEDED", payload: user });
} catch (e) {
yield put({ type: "FETCH_USER_FAILED", payload: e.message });
}
}
function* rootSaga() {
yield takeEvery("FETCH_USER_INFO", fetchUserInfo);
}
export default rootSaga;
takeEvery:他的作用是监听每个FETCH_USER_INFO,当FETCH_USER_INFO出现的时候,就调用fetchUserInfo函数,注意这里是每个FETCH_USER_INFO。也就是说如果同时发出多个FETCH_USER_INFO,我们每个都会响应并发起请求。takeLatest:takeLatest从名字都可以看出来,是响应最后一个请求,具体使用哪一个,要看具体的需求。
具体参考:https://juejin.cn/post/6885223002703822855
边栏推荐
- Calculus Learning
- The return values of hostname -f and uname -n may be different
- Is it safe for the top ten securities companies to open accounts? Is it reliable?
- 2022年7月产品经理认证招生简章(NPDP)
- 2022第六季完美童模 合肥赛区 决赛圆满落幕
- 闭关修炼(二十一)Servlet生命周期、service方法源码分析、线程安全问题
- “国防七校”之一西工大遭境外网络攻击
- Unity C# 网络学习(十二)——Protobuf生成协议
- cokkie和session的区别
- Did you really make things clear when you were promoted or reported?
猜你喜欢

Huawei equipment is configured with small network WLAN basic services

批量处理实验接触角数据-MATLAB分析

How to recite words in tables

Dialogue | prospects and challenges of privacy computing in the digital age

July 2022 (advanced soft test) information system project manager certification enrollment Brochure

2022年7月产品经理认证招生简章(NPDP)

uni-app获取当前页面路由url

Compare homekit, MI family, and zhiting family cloud edition for what scene based experiences

Actual combat memoir starts from webshell to break through the border

Baodawei of the people's Chain: break down barriers and establish a global data governance sharing and application platform
随机推荐
Backpack Lecture 9 - detailed understanding and code implementation
Measure the level of various chess playing activities through ELO mechanism
Sorting out easily confused words in postgraduate entrance examination English 【 flash 】
Open an account to buy funds. Is it safe to open an account through online funds-
背包九讲——全篇详细理解与代码实现
Cdga | what is the core of digital transformation in the transportation industry?
51单片机中断与定时器计数器,基于普中科技HC6800-ESV2.0
Batch processing of experimental contact angle data matlab analysis
P4769-[NOI2018]冒泡排序【组合数学,树状数组】
laravel 8 实现 订单表按月份水平分表
Huawei equipment is configured with small network WLAN basic services
js for in循环 for of循环的区别以及用法
Transformer details
ThreadLocal线程变量
通过ELO机制衡量各类对弈活动水平
How to recite words in tables
How to recover data loss of USB flash disk memory card
Wallpaper applet source code double ended wechat Tiktok applet
编程语言
成员内部类、静态内部类、局部内部类