由於一些團隊性的緣由,各個項目中一直在使用 Redux,所以我也一直忍受着 Redux 開發中的繁瑣。可是自從使用 React Hooks 以及 Redux v7.1.0 推出的 Hooks API 後,減小了很多樣板代碼,也解決了 Redux 在業務開發中缺乏某些功能的缺點。react
在以前的 class 組件中,是利用 HOC 方式來結合 Redux,具體就是 react-redux 的 connect 方法。然而這種方法須要寫不少樣板代碼,由於須要聲明 mapStateToProps 和 mapDispatchToProps。npm
import { connect } from 'react-redux';
const mapStateToProps = state => ({
counter: state.counter
});
const mapDispatchToProps = dispatch => ({});
connect(
mapStateToProps,
mapDispatchToProps
)(App);
複製代碼
由於樣板代碼繁瑣,因此你們很不喜歡對 Container 組件進行拆分,拆分一次可能就須要添加一遍上面的代碼。長此以往,Container 組件就變得愈來愈大,常常看見項目中會有 2000 行代碼的組件。通常 connect 方法的使用會放在組件文件結尾處,一個屏幕放不下那麼多行代碼,查閱 mapStateToProps 和 mapDispatchToProps 就須要在組件文件內跳來跳去。redux
來看看使用 Redux 的 Hooks API 的狀況。後端
import { useSelector, useDispatch } from 'react-redux';
function App() {
const counter = useSelector(state => state.counter);
const dispatch = useDispatch();
return (
<div>{counter}</div>
);
}
複製代碼
沒有 connect 方法,組件內直接引用 Redux state 數據,更容易進行組件的拆分,於是也不用在組件文件內大幅度轉移目光。數組
平常開發中,常常須要使用 Redux state 的衍生數據,例如:對後端返回的列表進行條件過濾。通常狀況下,咱們會寫一個 selector 函數,而後在 mapStateToProps 中引用這個函數。promise
// selectors.js
const listFilter = (list, condition) => {
// 根據 condition 過濾 list 數據,返回數組
};
// App.js
const mapStateToProps = state => ({
list: listFilter(state.list, state.condition)
});
複製代碼
一般狀況下,還能夠進行一些緩存操做,防止每次 state 數據變更都引起 listFilter 方法的從新執行,好比使用:reselect。緩存
在 React Hooks 中,能夠經過自定義 Hooks 函數來實現相應的功能。bash
import { useMemo } from 'react';
import { useSelector } from 'react-redux';
function useFilteredList() {
const list = useSelector(state => state.list);
const condition = useSelector(state => state.condition);
const getFilteredList = useMemo(() => {
// listFilter 來自上方代碼
const filteredList = listFilter(list, condition);
return () => filteredList;
}, [list, condition]);
return getFilteredList();
}
複製代碼
這樣只須要在組件內直接使用 useFilteredList 就能夠獲取通過條件過濾的列表數據,同時由於 useMemo 的功能,只有在依賴數組中 list, condition 變量變更的時候,listFilter 函數纔會從新執行。異步
另外在使用 useMemo 的時候,下方這樣的狀況是沒法實現緩存的效果的。async
const getFilteredList = useMemo(() => {
// listFilter 來自上方代碼
return () => listFilter(list, condition);
}, [list, condition]);
複製代碼
這種狀況下 useMemo 至關於 useCallback,由於返回的是一個計算函數,每次調用 getFilteredList 函數,都會從新執行 listFilter。
Redux 沒有提供配套的反作用的處理方法,須要結合其它庫,致使社區有一堆的解決方案可供選擇,像:redux-thunk、redux-saga、redux-promise等等。其實結合 React Hooks 就能夠很好的處理反作用。
舉個例子:咱們須要根據 id 來獲取這個 id 下的數據,並且須要將數據保存到 Redux store 中。這裏須要使用 react-use 的 useAsync 或 useAsyncFn 方法。
import { useDispatch } from 'react-redux';
import { useAsync } from 'react-use';
function useFetchItem(id) {
const dispatch = useDispatch();
return useAsync(async () => {
const response = await ...;
dispatch({
type: 'xxx',
response
});
return response;
}, [id]);
};
複製代碼
上面例子中聲明瞭一個自定義 Hooks 函數 useFetchItem,返回一個依賴於 id 變量的反作用函數,只要 id 變更,反作用函數就會從新執行。反作用函數中,使用 dispatch 方法發起了一個 Redux action 來執行相應的 reducer。
useAsync 返回值是關於 async 函數的狀態,它會有如下幾種狀態。
根據這幾個狀態,能夠完善 UI 的展現,也能夠減小以前在 redux-thunk 或 redux-saga 中一個異步反作用函數中屢次 dispatch 當前狀態的代碼。