ReactQuery 渲染优化示例详解
lakb248 人气:0引言
免责声明:渲染优化是所有应用的进阶话题。React Query已经进行了许多性能优化并且开箱即用,大多数时候不需要做更多优化。"不必要的重新渲染"是一个很多人投入大量关注的话题,也是我要写这篇文章的原因。但是我要再一次指出,大部分情况下对于大多数应用来说,渲染优化很可能并没有想得那么重要。重新渲染是一个好事情。它保证了你的应用展示了最新的状态。相比于重复渲染,我更关注由于缺少渲染而导致的渲染错误。对于更多关于这个话题的讨论,可以看下面的内容:
- Fix the slow render before you fix the re-render
- this article by @ryanflorence about premature optimizations
我在第二篇文章介绍select的内容中已经讲了一些关于渲染优化的事情。然而,"为什么在没有任何数据变化的情况下,React Query会渲染两次组件呢"是我平时被问到最多的一个问题。我们让我来尝试深入解释一下。
isFetching
在之前的例子中我说过,下面这个组件只会在todos的length变化时才会重新渲染,其实我只说了一部分事实:
export const useTodosQuery = (select) => useQuery(['todos'], fetchTodos, { select }) export const useTodosCount = () => useTodosQuery((data) => data.length) function TodosCount() { const todosCount = useTodosCount() return <div>{todosCount.data}</div> }
每次发生后台refetch的时候,这个组件都会下面的数据分别进行一次渲染:
{ status: 'success', data: 2, isFetching: true } { status: 'success', data: 2, isFetching: false }
这是因为React Query在每个查询中返回了很多基本信息,isFetching
就是其中一个。这个属性在请求正在发生的时候会被设置为true。这个在你想要展示一个后台请求的loading标志的时候特别有用。但是如果你不需要,那确实会造成一些不必要的渲染。
notifiOnChange
对于上面说到的这个场景,React Query提供了notifyOnChangeProps
参数。他可以在每个场景单独设置来告诉React Query:只在这些属性发生变化的时候再通知我。通过将这个参数设置为['data']
,我们可以实现一个新的版本:
export const useTodosQuery = (select, notifyOnChangeProps) => useQuery(['todos'], fetchTodos, { select, notifyOnChangeProps }) export const useTodosCount = () => useTodosQuery((data) => data.length, ['data'])
保持同步
尽管上面的代码可以正常工作,但是它很容易就会造成不同步。如果我们希望针对error
进行特殊处理呢?又或者我们需要使用isLoading
属性呢?我们不得不确保notifyOnChangeProps
属性和我们实际用到的数据保持同步。如果我们忘记将某个数据添加到属性里面,而只监听data属性的变化,当查询返回错误,同时我们也要展示这些错误的时候,我们的组件并不会重新渲染。这个问题当我们把这些属性写死在自定义hook的时候格外明显,因为我们并不知道使用自定义hook的组件实际上会用到哪些数据:
export const useTodosCount = () => useTodosQuery((data) => data.length, ['data']) function TodosCount() { //
加载全部内容
- 猜你喜欢
- 用户评论