资讯专栏INFORMATION COLUMN

React Hooks实现异步请求实例—useReducer、useContext和useEffec

RichardXG / 3613人阅读

摘要:本文是学习了年新鲜出炉的提案之后,针对异步请求数据写的一个案例。注意,本文假设了你已经初步了解的含义了,如果不了解还请移步官方文档。但不要忘记和上下文对象可以看做是写法的以及三个钩子函数的组合。

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

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写法。

函数签名

useReducer(reducer,initialState)

useContext(ctxObj)

useEffect(effectFunction,[dependencyValues])

概览-你需要编写什么

action.js:

我们还使用redux的思想,编写action

reducer.js:

处理action,不同于reduxreducer,这里我们可以不用提供初始状态

根组件:

Provider提供给子组件context

useReducer定义的位置,引入一个reducer并且提供初始状态initialState

子组件:

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传递给子组件
         
             //...
             //用到context的一个子组件
             
         
    )
}
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 (
        
{ //children }
) }

完整代码参见:branch:hooks-onlineShop

目录结构

我的目录结构大概这样:

src
  |- actions
     |- fetchAction.js
  |- components
     |-...
  |- reducers
     |- fetchReducer.js
  |- index.js
注意点

使用useContext()时候我们不需要使用Consumer了。但不要忘记exportimport上下文对象

useEffect()可以看做是class写法的componentDidMountcomponentDidUpdate以及componentWillUnMount三个钩子函数的组合。

当返回了一个函数的时候,这个函数就在compnentWillUnMount生命周期调用

默认地,传给useEffect的第一个参数会在每次(包含第一次)数据更新时重新调用

当给useEffect()传入了第二个参数(数组类型)的时候,effect函数会在第一次渲染时调用,其余仅当数组中的任一元素发生改变时才会调用。这相当于我们控制了组件的update生命周期

useEffect()第二个数组为空则意味着仅在componentDidMount周期执行一次

代码仓库里使用了Mock.js拦截api请求以及ant-design第三UI方库。目前代码比较简陋。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/58668.html

相关文章

  • React Hooks实现异步请求实例useReduceruseContextuseEffec

    摘要:本文是学习了年新鲜出炉的提案之后,针对异步请求数据写的一个案例。注意,本文假设了你已经初步了解的含义了,如果不了解还请移步官方文档。但不要忘记和上下文对象可以看做是写法的以及三个钩子函数的组合。 本文是学习了2018年新鲜出炉的React Hooks提案之后,针对异步请求数据写的一个案例。注意,本文假设了:1.你已经初步了解hooks的含义了,如果不了解还请移步官方文档。(其实有过翻译...

    Code4App 评论0 收藏0
  • 使用react hooks实现自己的context-redux

    摘要:首发自我的博客,欢迎注如要运行本文的代码,请先确认自己的版本已支持出来已经有段时间了,本文不对的具体用法作介绍,而是使用实现一个简易的基于的使用实现初版自带了供我们使用,它接受两个参数,一是函数,二是初始,并返回和函数,如下这个函数自己实现 首发自我的github博客,欢迎star 注:如要运行本文的代码,请先确认自己的react版本已支持hooks react hooks出来已经有段...

    Jackwoo 评论0 收藏0
  • 精读《Function Component 入门》

    摘要:比如就是一种,它可以用来管理状态返回的结果是数组,数组的第一项是值,第二项是赋值函数,函数的第一个参数就是默认值,也支持回调函数。而之所以输出还是正确的,原因是的回调函数中,值永远指向最新的值,因此没有逻辑漏洞。 1. 引言 如果你在使用 React 16,可以尝试 Function Component 风格,享受更大的灵活性。但在尝试之前,最好先阅读本文,对 Function Com...

    Scholer 评论0 收藏0
  • 十个案例学会 React Hooks

    摘要:在线传递给的是而不是,返回值即是想要透传的数据了。所以函数组件在每次渲染的时候如果有传递函数的话都会重渲染子组件。在学会使用React Hooks之前,可以先看一下相关原理学习React Hooks 前言 在 React 的世界中,有容器组件和 UI 组件之分,在 React Hooks 出现之前,UI 组件我们可以使用函数,无状态组件来展示 UI,而对于容器组件,函数组件就显得无能为力,我...

    williamwen1986 评论0 收藏0
  • React Hooks入门: 基础

    摘要:当组件安装和更新时,回调函数都会被调用。好在为我们提供了第二个参数,如果第二个参数传入一个数组,仅当重新渲染时数组中的值发生改变时,中的回调函数才会执行。 前言   首先欢迎大家关注我的Github博客,也算是对我的一点鼓励,毕竟写东西没法获得变现,能坚持下去也是靠的是自己的热情和大家的鼓励,希望大家多多关注呀!React 16.8中新增了Hooks特性,并且在React官方文档中新增...

    mrli2016 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<