原文: React Hooks使用实例(二)| AlloyTeam
做者:TAT.zhongzhong
在上篇文章咱们讲了如何使用React的Suspense组件和lazy方法来实现模块的懒加载,后面还讲了如何使用
React的useState方法来实现自定义的Hooks,从而达到复用的目的。html
咱们知道,无论在作什么样的前端项目,列表页确定是存在的,那如何获取列表的数据呢?大部分状况下咱们都是在每一个模块内部本身实现一个获取数据的方法,而后调用setState来更新数据。那有没有更好的方式能够作到这些,而且可以在一个项目中到处复用这个功能呢?答案就是使用React Hooks。前端
简单的说,useEffect就是在组件挂载完成或者更新完成的时候,须要执行的一系列操做,这些操做多是ajax请求,dom操做,事件处理等等。react
官方文档里面有句话说的是,useEffect是 componentDidMount, componentDidUpdate, 和 componentWillUnmount三个生命周期钩子的组合,那就是以前分别在这三个地方干的事情,如今能够统一在一个地方干了,是否是很方便?。为了保证文章简洁,这里不过多介绍,有须要能够参考官方文档ios
若是你用过redux,那你应该知道redux就是经过reducer来处理dispatch出来的各类action的。每一个reducer都是一个纯函数,处理完成以后,返回新的state,而后触发React的更新。官方文档ajax
先来分析下,咱们要从服务器获取数据,须要作哪些事情。redux
从上面的几个点咱们能够分析出,咱们的自定义Hook要可以传入请求人url以及请求的参数,在请求失败的时候可以有后台返回的提示信息,在请求成功的时候可以返回后台返回的数据,咱们还须要知道请求是否失败。axios
这里咱们将action拆分为3个:api
基于上面的分析,咱们先定义一个reducer,用来处理每一个action。数组
reducer.ts服务器
export const dataFetchReducer = (state: any, action: {[type: string]: any}) => { switch(action.type) { case 'FETCH_INIT': return { ...state, isLoading: true, isError: false } case 'FETCH_SUCCESS': return { ...state, isLoading: false, isError: false, data: action.payload } case 'FETCH_ERROR': return { ...state, isLoading: false, isError: true, msg: action.payload } default: throw new Error(`Unsupport action type:${action.type}`); } }
上面的reducer很是简单,就是处理上面咱们定义的三个action,而后每次都返回一个新的state,解释下上面返回的state的各个字段的用意:
介绍了reducer以后,咱们来看下Hook是什么实现的:
代码以下:
interface RequestConfig extends AxiosRequestConfig { url: string } export const useDataApi = (initData: Array<any> | any, initRequestConfig: RequestConfig) => { if (!initRequestConfig.method) { initRequestConfig.method = 'get'; } const [requestConfig, setRequestConfig] = useState(initRequestConfig); const [state, dispatch] = useReducer(dataFetchReducer, { data: initData, isLoading: false, isError: false }); useEffect(() => { const fetchData = async () => { try{ dispatch({ type: 'FETCH_INIT' }); if (!requestConfig.url) { dispatch({ type: 'FETCH_SUCCESS', payload: [] }); }else { const response = await axios(requestConfig).catch(e => { return e.response; }); if (response.data){ const data = response.data; const { success, result, message } = data; if (!success) { dispatch({ type: 'FETCH_ERROR', payload: message }); } else { dispatch({ type: 'FETCH_SUCCESS', payload: result }); } }else { dispatch({ type: 'FETCH_ERROR', msg: '加载数据失败' }); } } }catch(e) { dispatch({ type: 'FETCH_ERROR', msg: '加载失败' }); } }; fetchData(); }, [requestConfig]); return [state, setRequestConfig]; }
在上面的代码中,咱们定义了一个自定义的Hooks,名称为useDataApi,这个Hooks有2个参数,第一个参数是表示初始化时候的数据,第二个参数就是咱们请求须要用到的各类参数了。
上面的useState咱们就很少介绍了,主要来介绍下,下面代码中的useReducer。
const [state, dispatch] = useReducer(dataFetchReducer, { data: initData, isLoading: false, isError: false });
这里useReducer的第一个参数,就是传入咱们刚刚定义好的reducer,那个reducer里面咱们处理了3中类型的action,对不对?
第二个参数就是传入一个初始化的satte对象了。
而后看下这里的返回值,他是一个数组,为何要返回一个数组呢?
由于这样经过解构以后,你能够随意命名他们的两个返回值(一本正经)。
在上面的两个返回值中,第一个state是咱们渲染的时候须要用到的,第二个dispatch用来分发action的,这个dispatch分发的actio你,就会被咱们自定义的reducer去处理。
而后再来看下下面的useEffect的代码,这里代码比较多,咱们一点点看:
dispatch({ type: 'FETCH_INIT' });
上面的代码主要用来分发一个FETCH_INIT
的action,这个时候就回返回isLoading为true的state,组件根据这个来展现loading或者加载中...等提示。
const response = await axios(requestConfig).catch(e => { return e.response; });
这段代码就是具体的发送请求的代码,这里我使用了axios这个库,固然你也能够替换成别的库。
在请求完成以后,须要解析返回的结果,而后来决定是触发FETCH_SUCCESS
仍是触发FETCH_ERROR
action.
const data = response.data; const { success, result, message } = data; if (!success) { dispatch({ type: 'FETCH_ERROR', payload: message }); } else { dispatch({ type: 'FETCH_SUCCESS', payload: result }); }
这段代码,咱们获取response的data,而后解析data的数据,这里data就是后台返回的数据结构了,我这里后台返回的格式就是会包括这三个字段,success标识请求是否成功,result标识请求的结果,message表示提示信息,通常用来返回错误的提示信息。
到这里咱们自定义的Hooks就算完成了,而后咱们来看下怎么使用这个Hooks来加载数据。
const [{ isLoading, isError, msg, data }, setRequestConfig] = useDataApi([], { url: apiPath }); if (isError) { message.error(msg); } return ( <div> <div className="toolbar"> <Link to={window.location.pathname + "/detail"}> <Button type="primary" icon='plus'> 添加 </Button> </Link> </div> <CustomModal /> <Table columns={columns} dataSource={data} loading={isLoading} rowKey={'id'} /> </div> );
看上面的代码,是否是足够简单了?并且你能够再任何地方使用这个自定义的Hooks。
本篇文章主要讲了如下几个点:
AlloyTeam 欢迎优秀的小伙伴加入。
简历投递: alloyteam@qq.com
详情可点击 腾讯AlloyTeam招募Web前端工程师(社招)