由于一些团队性的缘由,各个项目中一直在使用 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 当前状态的代码。