Hooks异步请求实例-useReducer、useContext和useEffect替代Redux

121 篇文章 7 订阅
11 篇文章 1 订阅

 Hooks从诞生至今已经有了长足的进步,不得不说hooks的出现是React的一个标志性里程碑。用hooks来解决开发中的问题大大提升了我们日常工作的效率,本文是针对异步请求数据的一个案例,目前只针对useReducer、useContext、useEffect进行探讨,同时还需要使用过Redux进行过异步action添加。

分享每日一题:题目传送门

前端电子书大全:电子书

非Hooks实现方案

在React的生命周期中,我们知道componentDidMount里我们最适合去进行异步请求,因此在不需要考虑状态管理时,这种方法很简单:

class App extends React.Component{
    componentDidMount(){
        axios.get('/your/api')
            .then(res=>/*...*/)
    }
}

随后引入Redux进行状态管理

当你决定使用Redux进行状态管理时,比如将异步获取到的数据储存在store中,事情就开始复杂起来了。根据Redux的官方文档案例来看,为了实现异步action,你还得需要一个类似于redux-thunk、redux-saga的第三方库来解析你的异步action

Action.js: 定义异步请求action的地方

//这是一个异步action,分发了两个同步action,redux-thunk能够理解它
const fetchGoodsList = url => dispatch => {
    dispatch(requestGoodsList());
    axios.get(url)
        .then(res=>{
            dispatch(receiveGoodsList(res.data))
        })
};

Reducer.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>
        )
    }
}

 Component :进行异步请求的组件

class *** extends React.Component{
    //...
    componentDidMount(){
        this.props.url('your/url');
    }
    //...
}
const mapDispatchToProps={
    fetchGoodsList
}
export default connect(
    mapStateToProps,
    mapDispatchToProps
)(GoodsList);

 

使用Hooks-useReducer()useContext()

使用Redux很累,当然,你可以不使用Redux,直接通过props层层传递,或者使用context都可以。既然出了useReducer,使用到了Redux的思想,总要试着用一下。再麻烦也不会比redux麻烦了(手动狗头)

优点:

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

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

  1. useReducer(reducer,initialState)
  2. useContext(ctxObj)
  3. 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的情况下可以这样写) 

export const EditContext = React.createContext({});

// useReducer与useContext配合注入新的modal显示状态的控制信息**************************************
const initialVisiable = false;

const reducer = (visible: boolean, action: string) => {
  switch (action) {
    case 'show':
      return Boolean(1);
    case 'hide':
      return Boolean(0);

    default:
      return visible;
  }
};

之后需要在根组件的context()中传入相应参数,使得子组件可以获取到相应数据。 

const DataListManage: React.FC = props => {
 const dataManageList = useTestManageList();

 //reducer

 const [count, dispatch] = useReducer(reducer, initialVisiable);

 return (
 <PageHeaderLayout>
 <Card>
 <EditContext.Provider
 value={{
            visiState: count,
            visiDispatch: dispatch
 }}
 >
 <DataManageTable
 {...props}
 loading={dataManageList.loading}
 data={dataManageList.data}
 />
 </EditContext.Provider>
 </Card>
 </PageHeaderLayout>
  );
};

4、子组件

注意只有被
<***Context.Provider>包裹住的元素才能进行值与函数的传递

const onlyForSearch = value => {
    setSearchList(value);
  }; 


<tableContext.Provider
 value={{
          tabledata: dataset,
          setDataFunc: changeTableData,
          searchProps: searchState,
          controlSearchProps: throwStateToContral,
          searchList: searchList,
          onlyForSearchResult: onlyForSearch
 }}
 >
 <SearchBoxinTable />
...

5、子组件的子组件

在其中进行声明

 const searchDataSet = useContext(tableContext);
 ...
 // console.log(searchDataSet);
 searchDataSet.setDataFunc(searchResult.data.data.list);
 searchDataSet.controlSearchProps(true);
 searchDataSet.onlyForSearchResult({

需要注意的是:

1、无论在哪一层级进行context的声明,最终都可以通过provider进行向下的数据传递

2、context可以进行函数的传递,传递的参数在接收的子元素中进行数据传递回父组件,父组件接收到数据即可进行setState动态数据变更,促使组件render

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

3、不要在一个文件中provider提供完数据后,马上useContext消费数据,可能会取不到值。

Happy Hacking~~

 

 推荐阅读:

React的setState你真的用对了吗?

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

短暂又灿烂的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值