ReactQuery系列之数据转换示例详解
lakb248 人气:0引言
欢迎来到“关于react-query我不得不说的一些事情”的第二章节。随着我越来越深入这个库以及他的社区,我发现一些人们经常会问到的问题。最开始,我计划在一篇超长的文章里面把这些都讲清楚,最终我还是决定将他们拆分成一些有意义的主题。今天第一个主题是一个很普遍但是很重要的事情:数据转换。
数据转换
我们不得不面对这个问题-大部分的人并没有使用GraphQL。如果你使用了,那么恭喜你,因为你可以请求到你期望的数据格式。
如果你在使用REST风格的API,你就必须受限于后端返回的数据格式。所以在使用react-query的时候我们应该在什么地方通过什么方式来进行数据转换呢?
答案只有一个:看情况。
下面列举出四种进行数据转换的方式,以及他们的优缺点:
后端
这是我最喜欢的方式,如果你有决定权的话。如果后端返回的数据结构是你所期望的话,那么你就什么都不用做了。但是在很多场景这并不太现实,比如一些公共的REST API,特别是在企业级应用中。如果你可以让后端针对每一个具体的场景都有一个对应的接口,那么可以返回你期望的数据结构。
- 优点:
前端什么都不用做 - 缺点:
并不是所有情况下都能做到
查询函数中
查询函数是你传给useQuery
的函数。他会返回一个Promise,最终返回的数据会被存在缓存中。但是这并不意味着你只能按照后端给你的数据结构来返回数据。你可以在返回之前进行数据转换:
const fetchTodos = async (): Promise<Todos> => { const response = await axios.get('todos') const data: Todos = response.data return data.map((todo) => todo.name.toUpperCase()) } export const useTodosQuery = () => useQuery(['todos'], fetchTodos)
之后你就可以在其他地方使用转换之后的数据,仿佛后端返回的数据就是这样的。你在其他地方都不会拿到不是大写的todo名字了。同时你也拿不到数据的原始结构了。如果你查看react-query-devtools,你会看到转换之后的结构。如果你查看网络请求,你可以看到原始的数据结构。这个可能会有点让人感到困惑,所以不要忘了你在代码里面处理了数据结构。
同时,在这里react-query并不会做什么优化。也就是说每一次fetch被执行的时候,你的转换逻辑都会被执行。如果转换逻辑很复杂,需要考虑一下其他转换方式。一些公司在前端会有一个公共的API层来抽象数据获取,所以你可能没办法在这个抽象层里面做你的数据转换。
- 优点:
和API调用绑定在一起,对上层无感知 - 缺点:
在每次数据请求的时候都会运行
如果你有一个你无法修改的公共的API层,这个方式不太可行 - 其他:
存储在缓存中的是转换之后的数据结构,所以你没办法拿到原始的数据结构
render函数中
正如第一章节中介绍的,你可以自定义一个hook,那么你可以很方便的在这个hook里做数据转换:
const fetchTodos = async (): Promise<Todos> => { const response = await axios.get('todos') return response.data } export const useTodosQuery = () => { const queryInfo = useQuery(['todos'], fetchTodos) return { ...queryInfo, data: queryInfo.data?.map((todo) => todo.name.toUpperCase()), } }
正如代码逻辑所示,数据转换不会在每次数据查询的时候运行,但是会在每次render的时候运行(即使这次render并没有触发数据请求)。这看起来这不是什么大问题,如果你在意的话,你可以通过useMemo
来进行优化,同时尽可能只定义真正需要的依赖列表。queryInfo中的data
是引用稳定的除非数据真的发生了变化,但是queryInfo
就不是了。如果你把queryInfo
作为你的依赖,那么转换逻辑就会在每次render的时候运行:
export const useTodosQuery = () => { const queryInfo = useQuery(['todos'], fetchTodos) return { ...queryInfo, //
加载全部内容
- 猜你喜欢
- 用户评论