React Hooks实现异步请求实例—useReducer、useContext和useEffect代替Redux方案
本文是学习了2018年新鲜出炉的React Hooks提案之后,针对异步请求数据写的一个案例。注意,本文假设了:
1.你已经初步了解hooks的含义了,如果不了解还请移步官方文档。(其实有过翻译的想法,不过印记中文一直在翻译,就是比较慢啦)
2.你使用Redux实现过异步Action(非必需,只是本文不涉及该部分知识而直接使用)
3.你听说过axios或者fetch(如果没有,那么想象一下原生js的promise实现异步请求,或者去学习下这俩库)
全部代码参见仓库: github | Marckon选择hooks-onlineShop分支以及master分支查看
❗ 本文并非最佳实践,如有更好的方法或发现文中纰漏,欢迎指正!
前序方案(不想看可以直接跳过)
- 不考虑引入
Redux
通过学习React生命周期,我们知道适合进行异步请求的地方是componentDidMount钩子函数内。因此,当你不需要考虑状态管理时,以往的方法很简单:
class App extends React.Component{
componentDidMount(){
axios.get('/your/api')
.then(res=>/*...*/)
}
}
- 引入
Redux进行状态管理
当你决定使用Redux进行状态管理时,比如将异步获取到的数据储存在store中,事情就开始复杂起来了。根据Redux的官方文档案例来看,为了实现异步action,你还得需要一个类似于redux-thunk的第三方库来解析你的异步action。
requestAction.js: 定义异步请求action的地方
//这是一个异步action,分发了两个同步action,redux-thunk能够理解它
const fetchGoodsList = url => dispatch => {
dispatch(requestGoodsList());
axios.get(url)
.then(res=>{
dispatch(receiveGoodsList(res.data))
})
};
requestReducer.js: 处理同步action
const requestReducer=(state=initialState,action)=>{
switch (action.type) {
case REQUEST_GOODSLIST:
return Object.assign({},state,{
isFetching: true
});
case RECEIVE_GOODSLIST:
return Object.assign({},state,{
isFetching:false,
goodsList:action.goodsList
});
default:
return state;
}
};
App Component :你引入redux store和redux-thunk中间件的地方
import {Provider} from 'react-redux';
import thunkMiddleWare from 'redux-thunk';
import {createStore,applyMiddleware} from 'redux';
//other imports
let store=createStore(
rootReducer,
//这里要使用中间件,才能够完成异步请求
applyMiddleware(
thunkMiddleWare,
myMiddleWare,
)
);
class App extends React.Component{
render(){
return (
<Provider store={store}>
<RootComponent/>
</Provider>
)
}
}
GoodsList Component :需要进行异步请求的组件
class GoodsList extends React.Component{
//...
componentDidMount(){
this.props.fetchGoodsList('your/url');
}
//...
}
const mapDispatchToProps={
fetchGoodsList
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(GoodsList);
使用Hooks-useReducer()和useContext()
总之使用Redux很累,当然,你可以不使用Redux,直接通过props层层传递,或者使用context都可以。只不过本文我们学过了useReducer,使用到了Redux的思想,总要试着用一下。
这里你不需要引入别的任何第三方库了,简简单单地使用React@16.7.0-alpha.2版本就好啦
很重要的一点就是——函数式组件,现在React推荐我们这么做,可以基本上代替class写法。
函数签名
useReducer(reducer,initialState)useContext(ctxObj)useEffect(effectFunction,[dependencyValues])
概览-你需要编写什么
action.js:
- 我们还使用
redux的思想,编写action
- 我们还使用
reducer.js:
- 处理action,不同于
redux的reducer,这里我们可以不用提供初始状态
- 处理action,不同于
根组件:
Provider提供给子组件contextuseReducer定义的位置,引入一个reducer并且提供初始状态initialState
子组件:
useContext定义的位置,获取祖先组件提供的contextuseEffect用于进行异步请求
实现
1.action.js:我们使用action创建函数
const REQUEST_GOODSLIST = "REQUEST_GOODSLIST";
const RECEIVE_GOODSLIST = "RECEIVE_GOODSLIST";
//开始请求
const requestGoodsList = () => ({
type: REQUEST_GOODSLIST
});
//接收到数据
const receiveGoodsList = json => ({
type: RECEIVE_GOODSLIST,
goodsList: json.goodsList,
receivedAt: Date.now()
});
export {
RECEIVE_GOODSLIST,
REQUEST_GOODSLIST,
receiveGoodsList,
requestGoodsList,
}
2.reducer.js:判断action的类型并进行相应处理,更新state
import {
RECEIVE_GOODSLIST,
REQUEST_GOODSLIST,
} from "../..";
export const fetchReducer=(state,action)=>{
switch (action.type) {
case REQUEST_GOODSLIST:
return Object.assign({},state,{
isFetching: true
});
case RECEIVE_GOODSLIST:
return Object.assign({},state,{
isFetching:false,
goodsList:state.goodsList.concat(action.goodsList)
});
default:
return state;
}
};
3.根组件:引入reducer.js
import React,{useReducer} from 'react';
import {fetchReducer} from '..';
//创建并export上下文
export const FetchesContext = React.createContext(null);
function RootComponent() {
//第二个参数为state的初始状态
const [fetchesState, fetchDispatch] = useReducer(fetchReducer, {
isFetching: false,
goodsList: []
});
return (
//将dispatch方法和状态都作为context传递给子组件
<FetchesContext.Provider value={{fetchesState,dispatch:fetchDispatch}}>
//...
//用到context的一个子组件
<ComponentToUseContext/>
</FetchesContext.Provider>
)
}
4.子组件:引入FetchesContext
import {FetchesContext} from "../RootComponent";
import React, {useContext, useEffect,useState} from 'react';
import axios from 'axios';
function GoodsList() {
//获取上下文
const ctx = useContext(FetchesContext);
//一个判断是否重新获取的state变量
const [reFetch,setReFetch]=useState(false);
//具有异步调用副作用的useEffect
useEffect(() => {
//首先分发一个开始异步获取数据的action
ctx.dispatch(requestGoodsList());
axios.get(proxyGoodsListAPI())
.then(res=>{
//获取到数据后分发一个action,通知reducer更新状态
ctx.dispatch(receiveGoodsList(res.data))
})
//第二个参数reFetch指的是只有当reFetch变量值改变才重新渲染
},[reFetch]);
return (
<div onScroll={handleScroll}>
{
//children
}
</div>
)
}
完整代码参见:branch:hooks-onlineShop
目录结构
我的目录结构大概这样:
src
|- actions
|- fetchAction.js
|- components
|-...
|- reducers
|- fetchReducer.js
|- index.js
注意点
- 使用
useContext()时候我们不需要使用Consumer了。但不要忘记export和import上下文对象 useEffect()可以看做是class写法的componentDidMount、componentDidUpdate以及componentWillUnMount三个钩子函数的组合。- 当返回了一个函数的时候,这个函数就在
compnentWillUnMount生命周期调用 - 默认地,传给useEffect的第一个参数会在每次(包含第一次)数据更新时重新调用
- 当给
useEffect()传入了第二个参数(数组类型)的时候,effect函数会在第一次渲染时调用,其余仅当数组中的任一元素发生改变时才会调用。这相当于我们控制了组件的update生命周期 useEffect()第二个数组为空则意味着仅在componentDidMount周期执行一次
- 当返回了一个函数的时候,这个函数就在
- 代码仓库里使用了
Mock.js拦截api请求以及ant-design第三UI方库。目前代码比较简陋。
来源:https://segmentfault.com/a/1190000017209855
React Hooks实现异步请求实例—useReducer、useContext和useEffect代替Redux方案的更多相关文章
- react native 之异步请求
第一章 异步请求 fetch的运用 在react native 中异步请求一般用fetch这个方法, fetch的格式如下: const params ={ "charset" ...
- ajax异步请求实例
1. 问题分析 用户管理显示页面:usermanagement.tpl(也可以说是MVC中的V,即视图) 用户管理数据发送页面:usermanagement.php(也可以说是MVC中的M,即模型) ...
- XML异步请求实例
其实还是很格式化的: <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type&qu ...
- React Hooks简单业务场景实战(非源码解读)
前言 React Hooks 是React 16.7.0-alpha 版本推出的新特性.从 16.8.0 开始,React更稳定的支持了这一新特性. 它可以让你在不编写 class 的情况下使用 st ...
- [React] Refactor a Class Component with React hooks to a Function
We have a render prop based class component that allows us to make a GraphQL request with a given qu ...
- CAT中实现异步请求的调用链查看
CAT简介 CAT(Central Application Tracking),是美团点评基于 Java 开发的一套开源的分布式实时监控系统.美团点评基础架构部希望在基础存储.高性能通信.大规模在线访 ...
- 使用React Hooks新特性useReducer、useContext替代传统Redux高阶组件案例
当我们使用redux进行数据管理的时候,一般都是在根组件通过Provider的方式引入store,然后在每个子组件中,通过connect的方式使用高阶组件进行连接,这样造成的一个问题是,大量的高阶组件 ...
- 你真的会用react hooks?看看eslint警告吧!(如何发请求、提升代码性能等问题)
前言 看过几个react hooks 的项目,控制台上几百条警告,大多是语法不规范,react hooks 使用有风险,也有项目直接没开eslint.当然,这些项目肯定跑起来了,因为react自身或者 ...
- tornado异步请求响应速度的实例测试
tornado异步请求响应速度的实例测试
随机推荐
- Django【第1篇】:Django之MTV模型
Django框架第一篇基础 一个小问题: 什么是根目录:就是没有路径,只有域名..url(r'^$') 补充一张关于wsgiref模块的图片 一.MTV模型 Django的MTV分别代表: Model ...
- git详细使用教程
一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. 二:SVN与Git的最主要的区别? SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以 ...
- 与Swing的相识
参考自http://c.biancheng.net/swing/ Swing是一个用于Java GUI编程(图形界面设计)的工具包(类库):换句话说,java可以用来开发带界面的PC软件,使用到的工具 ...
- Java语言Lang包下常用的工具类介绍_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 无论你在开发哪中 Java 应用程序,都免不了要写很多工具类/工具函数.你可知道,有很多现成的工具类可用,并且代码质量都 ...
- win10如何设置软件开机启动
想要实现应用程序在所有的用户登录系统后都能自动启动,就把该应用程序的快捷方式放到“系统启动文件夹”里C:\ProgramData\Microsoft\Windows\Start Menu\Progra ...
- React Native 中 跨页面间通信解决方案之 react-native-event-bus
https://github.com/crazycodeboy/react-native-event-bus 用法: A页面和B页面中都有相同的列表,点击B页面中的收藏按钮,A页面会跟着更新 impo ...
- R语言预测实战(第二章--预测方法论)
2.1预测流程 从确定预测主题开始,一次进行数据收集.选择方法.分析规律.建立模型.评估效果直到发布模型. 2.2.1确定主题 (1)指标:表达的是数量特征,预测的结果也通常是通过指标的取值来体现. ...
- [CSP-S模拟测试]:毛二琛(DP)
题目描述 $MYC$在$NOI2018$中,遇到了$day1T2$这样一个题,题目是让你求有多少“好”的排列.$MYC$此题没有获得高分,感到非常惭愧,于是回去专心研究排列了.如今数排列的题对$MYC ...
- DB数据库的基本操作
启动 MongoDB 服务 sudo service mongodb start 进入 MongoDB 命令行操作界面,在命令行中敲 exit 可以退出.mongo 创建数据库 use db 命令查看 ...
- mui初级入门教程(四)— 再谈webview,从小白变“大神”!
文章来源:小青年原创发布时间:2016-06-05关键词:mui,html5+,webview转载需标注本文原始地址: http://zhaomenghuan.github.io/#!/blog/20 ...