按照来源,前端有两类「状态」需要管理:
在陈年的老项目中,通常用Redux、Mobx这样的「全局状态管理方案」无差别对待他们。
事实上,他们有很大区别:
用户交互的中间状态
比如组件的isLoading、isOpen,这类「状态」的特点是:
这类「状态」通常保存在组件内部。
当「状态」需要跨组件层级传递,通常使用Context API。
再大范围的「状态」会使用Redux这样的「全局状态管理方案」。
服务端状态
当我们从服务端请求数据:
- function App() {
- const [data, updateData] = useState(null);
- useEffect(async () => {
- const data = await axios.get('/api/user');
- updateData(data);
- }, [])
- // 处理data
- }
返回的数据通常作为「状态」保存在组件内部(如App组件的data状态)。
如果是需要复用的通用「状态」,通常将其保存在Redux这样的「全局状态管理方案」中。
这样做有2个坏处:
1.需要重复处理请求中间状态
为了让App组件健壮,我们还需要处理请求中、出错等中间状态:
- function App() {
- const [data, updateData] = useState(null);
- const [isError, setError] = useState(false);
- const [isLoading, setLoading] = useState(false);
- useEffect(async () => {
- setError(false);
- setLoading(true);
- try {
- const data = await axios.get('/api/user');
- updateData(data);
- } catch(e) {
- setError(true);
- }
- setLoading(false);
- }, [])
- // 处理data
- }
这类通用的中间状态处理逻辑可能在不同组件中重复写很多次。
2.「缓存」的性质不同于「状态」
不同于交互的中间状态,服务端状态更应被归类为「缓存」,他有如下性质:
作为可以由不同组件共享的「缓存」,还需要考虑更多问题,比如:
Redux一把梭固然方便。但是,区别对待不同类型「状态」能让项目更可控。
这里,推荐使用React-Query管理服务端状态。
另一个可选方案是SWR[1]。你可以从这里[2]看到他们的区别
初识React-Query
React-Query是一个基于hooks的数据请求库。
我们可以将刚才的例子用React-Query改写:
- import { useQuery } from 'react-query'
- function App() {
- const {data, isLoading, isError} = useQuery('userData', () => axios.get('/api/user'));
- if (isLoading) {
- return <div>loading</div>;
- }
- return (
- <ul>
- {data.map(user => <li key={user.id}>{user.name}</li>)}
- </ul>
- )
- }
React-Query中的Query指一个异步请求的数据源。
例子中userData字符串就是这个query独一无二的key。
可以看到,React-Query封装了完整的请求中间状态(isLoading、isError...)。
不仅如此,React-Query还为我们做了如下工作:
数据的CRUD由2个hook处理:
在下面的例子中,点击「创建用户」按钮会发起创建用户的post请求:
- import { useQuery, queryCache } from 'react-query';
- unction App() {
- const {data, isLoading, isError} = useQuery('userData', () => axios.get('/api/user'));
- // 新增用户
- const {mutate} = useMutation(data => axios.post('/api/user', data));
- return (
- <ul>
- {data.map(user => <li key={user.id}>{user.name}</li>)}
- <button
- onClick={() => {
- mutate({name: 'kasong', age: 99})
- }}
- >
- 创建用户
- </button>
- </ul>
- )
但是点击后userData query对应数据不会更新,因为他还未失效。
所以我们需要告诉React-Query,userData query对应的缓存已经失效,需要更新:
- import { useQuery, queryCache } from 'react-query';
- function App() {
- // ...
- const {mutate} = useMutation(userData => axios.post('/api/user', userData), {
- onSuccess: () => {
- queryCache.invalidateQueries('userData')
- }
- })
- // ...
- }
通过调用mutate方法,会触发请求。
当请求成功后,会触发onSuccess回调,回调中调用queryCache.invalidateQueries,将userData对应的query缓存置为invalidate。
这样,React-Query就会重新请求userData对应query的数据。
总结
通过使用React-Query(或SWR)这样的数据请求库,可以将服务端状态从全局状态中解放出来。
这为我们带来很多好处:
参考资料
[1]SWR: https://swr.vercel.app/
[2]这里: https://react-query.tanstack.com/comparison
美家全域潜客运营解决方案 借助阿里平台能力打通线上、门店周边、到店和离店链路...
欢迎使用阿里云开发者工具套件(SDK)。阿里云Node.js SDK让您不用复杂编程即可...
近日,一月一更新的 TIOBE 编程社区揭晓了2021年2月各大编程语言的排行情况,从...
描述 给出一个小数数组A,一个非负整数target。对A中的每个小数进行向上取整或者...
近日,亚马逊云科技宣布Amazon Lookout for Vision正式可用,这是一项全新服务,...
本文转载自微信公众号「程序新视界」,作者二师兄 。转载本文请联系程序新视界公...
Go 语言的并发特性是其一大亮点,今天我们来带着大家一起看看如何使用 Go 更好地...
近日,中国人民银行发布关于《征信业务管理办法(征求意见稿)》(下称《办法》),...
周运(戒刀) 一、针对数字化应用方向进行未来整体蓝图规划 规划蓝图主要分为三...
如果您通过镜像文件注册私有镜像时勾选了“进行后台自动化配置”,那么后台系统...