📌
useSWRのパフォーマンスを損なわずカスタムフックを作成する
useSWRはコンポーネントによって使用されている状態のみを更新します。
useSWRを使って、data
やisValidating
を渡す以下のようなカスタムフックを作ると、このメリットが損なわれてしまいます。
import useSWR, { SWRConfiguration } from 'swr'
import { get, post } from './fetcher'
import { User } from './types'
const useUser = (userId: string, option?: SWRConfiguration) => {
const { mutate, ...other } = useSWR<User>(`/users/${userId}`, get, option)
const update = (newUserValue: User) =>
mutate(async prevUser => {
post(`/users/${userId}`, newUserValue)
return newUserValue
}, false)
return { mutate, ...other, update }
}
このようなカスタムフックだと、updateしか使わないコンポーネントでも、dataが更新されるたびレンダリングが発生します。さらにotherにはisValidatingやerrorも含まれているのでこれらの値が更新されるたびにもレンダリングします。(計4回ほど)
これを回避するためには、スプレッド構文を使わずにObject.assignで返します。
import useSWR, { SWRConfiguration } from 'swr'
import { get, post } from './fetcher'
import { User } from './types'
const useUser = (userId: string, option?: SWRConfiguration) => {
const swrResponse = useSWR<User>(`/users/${userId}`, get, option)
const { mutate } = swrResponse
const update = (newUserValue: User) =>
mutate(async prevUser => {
post(`/users/${userId}`, newUserValue)
return newUserValue
}, false)
return Object.assign(swrResponse, { update })
}
本当はupdateもメモ化していたほうがいいでしょうね。
Discussion