用React-query解决你一半的状态管理问题

 按照来源,解决半前端有两类「状态」需要管理:

用户交互的态管题中间状态 服务端状态

在陈年的老项目中,通常用Redux、理问Mobx这样的解决半「全局状态管理方案」无差别对待他们。

事实上,态管题他们有很大区别:

用户交互的理问中间状态

比如组件的isLoading、isOpen,解决半这类「状态」的态管题特点是:

以「同步」的形式更新 「状态」完全由前端控制 「状态」比较独立(不同的组件拥有各自的isLoading)

这类「状态」通常保存在组件内部。

当「状态」需要跨组件层级传递,理问通常使用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 } 

这类通用的云南idc服务商中间状态处理逻辑可能在不同组件中重复写很多次。

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还为我们做了如下工作:

多个组件请求同一个query时只发出一个请求 缓存数据失效/更新策略(判断缓存合适失效,失效后自动请求数据) 对失效数据垃圾清理

数据的CRUD由2个hook处理:

useQuery处理数据的查 useMutation处理数据的增/删/改

在下面的例子中,点击「创建用户」按钮会发起创建用户的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)这样的数据请求库,可以将服务端状态从全局状态中解放出来。

这为我们带来很多好处:

使用通用的hook处理请求中间状态 多余请求合并 针对缓存的更新/失效策略 Redux等「全局状态管理方案」可以更专注于「前端中间状态」处理

参考资料

[1]SWR: https://swr.vercel.app/

[2]这里: https://react-query.tanstack.com/comparison

 【编辑推荐】

为什么你总是学不会Python,香港云服务器入门Python的4大陷阱 厌倦了默认系统字体?这是在Windows 10上进行更改的方法 5G手机热销之前,要先解决这些问题 手把手教你用Python爬取百度搜索结果并保存 揭秘登上2021春晚舞台的黑科技-XR技术
系统运维
上一篇:国内域名
下一篇:为什么起域名意义非凡?起域名有什么名堂?