当我们使用redux
进行数据管理的时候,一般都是在根组件通过Provider
的方式引入store
,然后在每个子组件中,通过connect
的方式使用高阶组件进行连接,这样造成的一个问题是,大量的高阶组件代码冗余度特别高,既然hooks
带来了新特性,不如一起来用用看
目录结构图
1 2 3 4 5 6 7
| ├── otherPage | ├── index.jsx ├── Test | ├── child.jsx | ├── index.jsx | ├── otherPage.jsx | └── reducer.jsx
|
效果图
![效果图]()
实现
Test/reducer.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import axios from 'axios';
function reducer (state, action) { switch (action.type) { case 'ADD': return Object.assign({}, state, { type: 'add', index: ++state.index }); case 'DOWN': return Object.assign({}, state, { type: 'down', index: --state.index }); case 'FETCH': axios('/addFetch').then((result) => { console.log(result); }).catch((err) => { console.log(err); }); ; return Object.assign({}, state); default: return Object.assign({}, state, { index: 1 }); } };
export default reducer;
|
Test/child.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import React, { useContext, useEffect } from 'react'; import { FetContext } from './index'; import { Button } from 'antd-mobile';
function DeepChild (props) { const dispatch = useContext(FetContext);
function handleClick () { dispatch({ type: 'ADD' }); }
const fetch = () => { console.log('fetch'); dispatch({ type: 'FETCH' }); };
useEffect(() => { console.log('child useEffect', props); });
return ( <div> <Button onClick={handleClick} type='primary'>Child Add</Button> <br /> <Button onClick={fetch} type='primary'>Child Request</Button> <br /> </div> ); }
export default DeepChild;
|
Test/index.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| import React, { useReducer, useEffect } from 'react'; import reducer from './reducer'; import DeepChild from './child'; import { Button, InputItem } from 'antd-mobile'; export const FetContext = React.createContext(null);
function Test (props) { const [state, dispatch] = useReducer(reducer, { isFetching: false, index: props.location.state.index || 1 });
useEffect(() => { });
const fetch = () => { dispatch({ type: 'FETCH' }); };
const confirmClick = () => { dispatch({ type: 'DOWN' }); };
const goOtherPage = () => { props.history.push({ pathname: 'otherPage', state: { index: state.index } }); };
const reset = () => { dispatch({ type: 'RESET' }); };
return ( <FetContext.Provider value={dispatch}> <InputItem value={state.index} /> <DeepChild {...state} /> <Button onClick={confirmClick} type='warning'>Parent Reduce</Button> <br /> <Button type='warning' onClick={fetch}>Parent Request!</Button> <br /> <Button type='primary' onClick={reset}>Reset Index</Button> <br /> <Button type='ghost' onClick={goOtherPage}>Next Page</Button> </FetContext.Provider> ); }
export default Test;
|
OtherPage/index.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import React, { useReducer, useEffect } from 'react'; import reducer from '../Test/reducer'; import { InputItem, Button } from 'antd-mobile';
function OtherPage (props) { const [state, dispatch] = useReducer(reducer, props.location.state);
useEffect(() => { console.log('OtherPage props', state); });
const add = () => { dispatch({ type: 'ADD' }); };
const goBack = () => { console.log('123'); console.log('props', props); props.history.replace({ pathname: 'Test', state: { index: state.index } }); };
return ( <div> <InputItem value={state.index} /> <Button onClick={add} type='primary'> add</Button> <br /> <Button onClick={goBack} type='ghost'> Go Back</Button> </div> ); }
export default OtherPage;
|
注意点
useEffect()
可以看做是class
写法的componentDidMount
、componentDidUpdate
以及componentWillUnMount
三个钩子函数的组合。
- 当返回了一个函数的时候,这个函数就在
compnentWillUnMount
生命周期调用
- 默认地,传给
useEffect
的第一个参数会在每次(包含第一次)数据更新时重新调用
- 当给
useEffect()
传入了第二个参数(数组类型)的时候,effect
函数会在第一次渲染时调用,其余仅当数组中的任一元素发生改变时才会调用。这相当于我们控制了组件的update
生命周期
useEffect()
第二个数组为空则意味着仅在componentDidMount
周期执行一次