本文是学习了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);

完整代码:branch:master-onlineShop

使用Hooks-useReducer()useContext()

总之使用Redux很累,当然,你可以不使用Redux,直接通过props层层传递,或者使用context都可以。只不过本文我们学过了useReducer,使用到了Redux的思想,总要试着用一下。

这里你不需要引入别的任何第三方库了,简简单单地使用React@16.7.0-alpha.2版本就好啦

很重要的一点就是——函数式组件,现在React推荐我们这么做,可以基本上代替class写法。

函数签名

  1. useReducer(reducer,initialState)
  2. useContext(ctxObj)
  3. useEffect(effectFunction,[dependencyValues])

概览-你需要编写什么

  1. action.js:

    • 我们还使用redux的思想,编写action
  2. reducer.js:

    • 处理action,不同于reduxreducer,这里我们可以不用提供初始状态
  3. 根组件:

    • Provider提供给子组件context
    • useReducer定义的位置,引入一个reducer并且提供初始状态initialState
  4. 子组件:

    • useContext定义的位置,获取祖先组件提供的context
    • useEffect用于进行异步请求

实现

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

注意点

  1. 使用useContext()时候我们不需要使用Consumer了。但不要忘记exportimport上下文对象
  2. useEffect()可以看做是class写法的componentDidMountcomponentDidUpdate以及componentWillUnMount三个钩子函数的组合。

    • 当返回了一个函数的时候,这个函数就在compnentWillUnMount生命周期调用
    • 默认地,传给useEffect的第一个参数会在每次(包含第一次)数据更新时重新调用
    • 当给useEffect()传入了第二个参数(数组类型)的时候,effect函数会在第一次渲染时调用,其余仅当数组中的任一元素发生改变时才会调用。这相当于我们控制了组件的update生命周期
    • useEffect()第二个数组为空则意味着仅在componentDidMount周期执行一次
  3. 代码仓库里使用了Mock.js拦截api请求以及ant-design第三UI方库。目前代码比较简陋。

来源:https://segmentfault.com/a/1190000017209855

React Hooks实现异步请求实例—useReducer、useContext和useEffect代替Redux方案的更多相关文章

  1. react native 之异步请求

    第一章 异步请求  fetch的运用 在react native  中异步请求一般用fetch这个方法, fetch的格式如下: const params ={ "charset" ...

  2. ajax异步请求实例

    1. 问题分析 用户管理显示页面:usermanagement.tpl(也可以说是MVC中的V,即视图) 用户管理数据发送页面:usermanagement.php(也可以说是MVC中的M,即模型) ...

  3. XML异步请求实例

    其实还是很格式化的: <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type&qu ...

  4. React Hooks简单业务场景实战(非源码解读)

    前言 React Hooks 是React 16.7.0-alpha 版本推出的新特性.从 16.8.0 开始,React更稳定的支持了这一新特性. 它可以让你在不编写 class 的情况下使用 st ...

  5. [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 ...

  6. CAT中实现异步请求的调用链查看

    CAT简介 CAT(Central Application Tracking),是美团点评基于 Java 开发的一套开源的分布式实时监控系统.美团点评基础架构部希望在基础存储.高性能通信.大规模在线访 ...

  7. 使用React Hooks新特性useReducer、useContext替代传统Redux高阶组件案例

    当我们使用redux进行数据管理的时候,一般都是在根组件通过Provider的方式引入store,然后在每个子组件中,通过connect的方式使用高阶组件进行连接,这样造成的一个问题是,大量的高阶组件 ...

  8. 你真的会用react hooks?看看eslint警告吧!(如何发请求、提升代码性能等问题)

    前言 看过几个react hooks 的项目,控制台上几百条警告,大多是语法不规范,react hooks 使用有风险,也有项目直接没开eslint.当然,这些项目肯定跑起来了,因为react自身或者 ...

  9. tornado异步请求响应速度的实例测试

    tornado异步请求响应速度的实例测试

随机推荐

  1. python 使用wxpy实现获取微信好友列表 头像 群成员

    最近在学习 python 突然想要试试能不能把微信里面的微信群和好友取出来 结果百度了一下 找到了 wxpy 这怎么能不试一下呢 用到 wxpy.threading.os.time 四个库 第一步 判 ...

  2. 【ZJOI2008】树的统计

    题目 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: ...

  3. 【leetcode】1144. Decrease Elements To Make Array Zigzag

    题目如下: Given an array nums of integers, a move consists of choosing any element and decreasing it by ...

  4. 【rust】rust安装,运行第一个Rust 程序 (1)

    安装 Rust 在 Unix 类系统如 Linux 和 macOS 上,打开终端并输入: curl https://sh.rustup.rs -sSf | sh 回车后安装过程出现如下显示: info ...

  5. Solr分组查询

     项目中需要实时的返回一下统计的东西,因此就要进行分组,在获取一些东西,代码拿不出来,因此分享一篇,还是很使用的. facet搜索 /** * * 搜索功能优化-关键词搜索 * 搜索范围:商品名称.店 ...

  6. Redis-cli相关命令

    > flushdb > SELECT OK []> GET db_number (nil) []> []> flushdb OK []> SELECT OK > ...

  7. 洛谷P1310 表达式的值——题解

    题目传送 题的难点:1.有运算优先级,不好判断.2.有破坏整体和谐性的讨厌的括号.3.不知道哪里要填数.4.要求方案数很大,搜索不会做呐. 发现难点1和2都是中缀表达式的缺点.转成后缀表达式后难点1. ...

  8. elasticsearch堆内存的配置建议

    1.将最小堆大小(Xms)和最大堆大小(Xmx)设置为彼此相等 防止内存抖动 2:给多大的堆内存? 给ES的内存配置不是越大越好,建议不能超过32GB,不同jdk版本最大边界值是不同的,对于32位小于 ...

  9. cookie存储userID所遇到的问题

    *)问题:control charater in cookie value or attribute 转自:https://blog.csdn.net/weixin_36380516/article/ ...

  10. java创建对象方法列表

    引用 不用构造方法也能创建对象 前言 java中对象创建的方法主要包括,1,使用new关键字,2.使用clone方法,3.反射机制,4.反序列化.其中1,3都会明确的显式的调用构造函数.2是在内存上对 ...