10000 React Hooks实现异步请求实例—useReducer、useContext和useEffect代替Redux方案 · Issue #3 · xianzou/blog · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
React Hooks实现异步请求实例—useReducer、useContext和useEffect代替Redux方案 #3
Open
@xianzou

Description

@xianzou

此本转载至Marckon的文章:

React Hooks实现异步请求实例—useReducer、useContext和useEffect代替Redux方案
原文地址;

使用Hooks-useReducer()useContext()

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

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

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

函数签名

  • useReducer(reducer,initialState)

  • useContext(ctxObj)

  • 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>
    )
}

我的目录结构大概这样:

src
  |- actions
     |- fetchAction.js
  |- components
     |-...
  |- reducers
     |- fetchReducer.js
  |- index.js

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

注意点

  1. 使用useContext()时候我们不需要使用Consumer了。但不要忘记exportimport上下文对象
  2. useEffect()可以看做是class写法的componentDidMountcomponentDidUpdate以及componentWillUnMount三个钩子函数的组合。
    • 当返回了一个函数的时候,这个函数就在compnentWillUnMount生命周期调用
    • 默认地,传给useEffect的第一个参数会在每次(包含第一次)数据更新时重新调用
    • 当给useEffect()传入了第二个参数(数组类型)的时候,effect函数会在第一次渲染时调用,其余仅当数组中的任一元素发生改变时才会调用。这相当于我们控制了组件的update生命周期
    • useEffect()第二个数组为空则意味着仅在componentDidMount周期执行一次
  3. 代码仓库里使用了Mock.js拦截api请求以及ant-design第三UI方库。目前代码比较简陋。

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0