本文是进修了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 (
<Provider store={store}>
<RootComponent/>
</Provider>
)
}
}
GoodsList Component :须要举行异步要求的组件
class GoodsList extends React.Component{
//...
componentDidMount(){
this.props.fetchGoodsList('your/url');
}
//...
}
const mapDispatchToProps={
fetchGoodsList
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(GoodsList);
运用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,不同于
redux
的reducer
,这里我们可以不必供应初始状况
- 处置惩罚action,不同于
根组件:
-
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通报给子组件
<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>
)
}
完全代码拜见:branch:hooks-onlineShop
目次构造
我的目次构造也许如许:
src
|- actions
|- fetchAction.js
|- components
|-...
|- reducers
|- fetchReducer.js
|- index.js
注重点
- 运用
useContext()
时刻我们不须要运用Consumer
了。但不要遗忘export
和import
上下文对象 useEffect()
可以看作是class
写法的componentDidMount
、componentDidUpdate
以及componentWillUnMount
三个钩子函数的组合。- 当返回了一个函数的时刻,这个函数就在
compnentWillUnMount
生命周期挪用 - 默许地,传给useEffect的第一个参数会在每次(包括第一次)数据更新时从新挪用
- 当给
useEffect()
传入了第二个参数(数组范例)的时刻,effect函数会在第一次衬着时挪用,其他仅当数组中的任一元素发作转变时才会挪用。这相当于我们掌握了组件的update
生命周期 -
useEffect()
第二个数组为空则意味着仅在componentDidMount
周期实行一次
- 当返回了一个函数的时刻,这个函数就在
- 代码堆栈里运用了
Mock.js
阻拦api要求以及ant-design
第三UI方库。现在代码比较大略。