React Hook借助useReducer, useContext代替Redux方案
-
- 目錄結構圖
- 效果圖
- 實作
-
- `Test/reducer.jsx`
- `Test/child.jsx`
- `Test/index.jsx`
- `OtherPage/index.jsx`
- 注意點
當我們使用進行資料管理的時候,一般都是在根元件通過
redux
的方式引入
Provider
,然後在每個子元件中,通過
store
的方式使用高階元件進行連接配接,這樣造成的一個問題是,大量的高階元件代碼備援度特别高,既然
connect
帶來了新特性,不如一起來用用看
hooks
目錄結構圖

├── otherPage // 其他頁面
| ├── index.jsx // 共享`Test`頁面的狀态;
├── Test // 測試頁面
| ├── child.jsx // 測試頁面的子元件。1、`useContext`定義的位置,擷取父元件提供的`context`;2、`useEffect`進行異步請求;
| ├── index.jsx // 測試頁面父元件。1、通過使用`Provider`提供給子元件`context`;2、`useReducer`定義的位置,引入一個`reducer`并且提供初始狀态`initialState`;
| ├── otherPage.jsx // 其他頁面,已删除~~
| └── reducer.jsx // 處理不同類型的`action`操作
效果圖
實作
Test/reducer.jsx
Test/reducer.jsx
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
Test/child.jsx
import React, { useContext, useEffect } from 'react';
import { FetContext } from './index';
import { Button } from 'antd-mobile';
function DeepChild (props) {
// If we want to perform an action, we can get dispatch from context.
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
Test/index.jsx
/* eslint-disable react/prop-types */
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
OtherPage/index.jsx
/* eslint-disable react/prop-types */
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.go(-1);
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
- 當傳回了一個函數的時候,這個函數就在