当前位置: 首页 > Web前端 > HTML5

ReactHooks实现异步请求实例——useReducer、useContext、useEffect替代Redux解决方案

时间:2023-04-05 23:37:48 HTML5

本文是在学习了2018年刚出炉的ReactHooks提案后,针对异步请求数据编写的案例。注意,本文假设:1.你有一个初步了解hooks的含义,不明白的请移步官方文档。(其实我有翻译的想法,但是ImprintChinese一直在翻译,但是比较慢)2.你用过Redux实现异步Action(没必要,但是本文不涉及这部分知识和你可以直接使用它)3.你听说过吗?axios或者fetch(没有的话,想象一下原生js实现异步请求的承诺,或者学习这两个库)所有代码都可以在仓库找到:github|Marckon选择hooks-onlineShop分支和master分支查看?本文不是最佳实践,如果大家有更好的方法或者发现文中有错误,欢迎指正!预购计划(不想看的可以跳过)不考虑引入Redux。通过学习React生命周期,我们知道适合异步请求的地方在componentDidMount钩子函数中。所以当你不需要考虑状态管理的时候,之前的做法很简单:..*/)}}引入Redux进行状态管理当您决定使用Redux进行状态管理时,例如在商店中存储异步检索的数据,事情开始变得复杂起来。根据Redux的官方文档,要实现异步动作,你需要一个类似于redux-thunk的第三方库来解析你的异步动作。requestAction.js:定义异步请求动作的地方//这是一个异步动作,分发两个同步动作,redux-thunk可以理解constfetchGoodsList=url=>dispatch=>{dispatch(requestGoodsList());公理。get(url).then(res=>{dispatch(receiveGoodsList(res.data))})};requestReducer.js:处理同步actionconstrequestReducer=(state=initialState,action)=>{switch(action.type){caseREQUEST_GOODSLIST:returnObject.assign({},state,{isFetching:true});caseRECEIVE_GOODSLIST:returnObject.assign({},state,{isFetching:false,goodsList:action.goodsList});默认值:返回状态;}};AppComponent:引入reduxstore和redux-thunk中间件的地方//otherimportsletstore=createStore(rootReducer,//这里需要使用中间件来完成异步请求applyMiddleware(thunkMiddleWare,myMiddleWare,));classAppextendsReact.Component{render(){return()}}GoodsList组件:需要做异步的组件请求类GoodsList扩展React.Component{//...componentDidMount(){this.props.fetchGoodsList('your/url');}//...}constmapDispatchToProps={fetchGoodsList}exportdefaultconnect(mapStateToProps,mapDispatchToProps)(GoodsList);完整代码:分支: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的思想写actionreducer.js:处理action,与reduxreducer不同,这里我们不需要提供初始状态根组件:Provider提供子组件contextuseReducer定义的位置,引入一个reducer并提供初始状态initialState子组件:useContext定义的位置,获取提供的contextuseEffect通过异步请求实现的祖先组件1.action.js:我们使用action创建函数constREQUEST_GOODSLIST="REQUEST_GOODSLIST";constRECEIVE_GOODSLIST="RECEIVE_GOODSLIST";//开始请求constrequestGoodsList=()=>({type:REQUEST_GOODSLIST});//接收数据constreceiveGoodsList=json=>({type:RECEIVE_GOODSLIST,goodsList:json.goodsList,receivedAt:Date.now()});export{RECEIVE_GOODSLIST,REQUEST_GOODSLIST,receiveGoodsList,requestGoodsList,}2.reducer.js:判断动作类型并执行相应动作流程,更新stateimport{RECEIVE_GOODSLIST,REQUEST_GOODSLIST,}from"../..";exportconstfetchReducer=(state,action)=>{switch(action.type){caseREQUEST_GOODSLIST:returnObject.assign({},state,{isFetching:true});caseRECEIVE_GOODSLIST:returnObject.assign({},state,{isFetching:false,goodsList:state.goodsList.concat(action.goodsList)});默认值:返回状态;}};3.根组件:importreducer.jsimportReact,{useReducer}from'react';import{fetchReducer}from'..';//创建并导出上下文exportconstFetchesContext=React.createContext(null);functionRootComponent(){//第二个参数是状态的初始状态const[fetchesState,fetchDispatch]=useReducer(fetchReducer,{isFetching:false,goodsList:[]});return(//dispatch方法state和status都作为context传递给子组件//...//使用context的子组件)}4.子组件:引入FetchesContextimport{FetchesContext}from"../RootComponent";importReact,{useContext,useEffect,useState}from'react';importaxiosfrom'axios';functionGoodsList(){//获取上下文constctx=useContext(FetchesContext);//判断是否重新取数据的状态变量const[reFetch,setReFetch]=useState(false);//具有异步调用副作用的useEffectuseEffect(()=>{//首先调度一个动作开始异步获取数据ctx.dispatch(requestGoodsList());axios.get(proxyGoodsListAPI()).then(res=>{//获取到数据后分发一个action,通知reducer更新状态ctx.dispatch(receiveGoodsList(res.data))})//第二个参数reFetch是指只有reFetch变量的值时才重新渲染更改},[重新获取]);return({//children}

)}查看完整代码:branch:hooks-onlineShop目录结构我的目录结构大致是这样的:src|-actions|-fetchAction.js|-components|-...|-reducers|-fetchReducer.js|-index.js注意使用useConte我们在使用xt()的时候不需要使用Consumer,但是别忘了export和import上下文对象useEffect()可以看做是三个钩子函数的组合:componentDidMount、componentDidUpdate和componentWillUnMount写在类中。当返回一个函数时,这个函数在compnentWillUnMount生命周期中被调用。默认情况下,每次(包括第一次)数据更新时,都会再次调用传递给useEffect的第一个参数。当传递给useEffect()第二个参数(数组类型)时,效果函数会在第一次渲染时被调用,其余的只会在数组中的任何元素发生变化时被调用。这相当于我们控制了组件的更新生命周期。UseEffect()第二个数组为空,也就是说在componentDidMount循环中只执行一次。代码仓库中使用Mock.js拦截API请求和ant-design第三方UI库。目前的代码比较简单。

最新推荐
猜你喜欢