【Remix × SSR】clientLoaderから取得したデータをコンポーネントにマッピングする際にはHydrateFallBackを忘れずに
https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2L6YRAyItykuOBqVWyAYmjHJqhyphenhyphenuaAaN6Kl68ie4QPAlr1Gp-Qaf9_cP9yFuxbHvUgYZaJyjPMJ7QXjjZLrzcacYdylRqBPBbZWf1t8Nt7nGI7bfacoHv2HtWI-ERXgxHshJnThj8Gg4/s800/koutsu_seiri.png
【前提】
code:route.tsx
export const clientLoader = async() => {
const res = await getUserData()
return {
user: res.user
}
}
export default function Index() {
const { user } = userLoaderData<typeof clientLoader>()
return(
<>
<p>ユーザー名: {user.name}</p>
</>
)
}
clientLoaderはハイドレーション時に実行されるので、SSRによるリクエスト時にはuser.nameは表示されないことになります。このような現象を防ぐ場合にはどうすればよいのでしょうか
【結論】
HydrateFallbackを利用します。このフォールバック関数はclientLoaderが実行されるまでコンポーネントのレンダリングを待機してSSR中は他のコンポーネントをレンダリングします。こちらを利用することで、clientLoaderで取得したデータのマッピングが完了したコンポーネントをレンダリングすることができます。 上記のコードを以下のように改修します。
code:route.tsx
export const clientLoader = async() => {
const res = await getUserData()
return {
user: res.user
}
}
// HydrateFallbackを追加
export function HydrateFallback() {
return <p>ユーザーデータを取得中です…</p>
}
export default function Index() {
const { user } = userLoaderData<typeof clientLoader>()
return(
<>
<p>ユーザー名: {user.name}</p>
</>
)
}
こうすることでSSR時にはclientLoaderの実行が完了するまでユーザーデータを取得中です…が表示され、clientLoaderの実行が完了するとルートコンポーネントがレンダリングされます。
【余談】
上記の条件に追加してloaderとclientLoaderを定義している場合も同様に、HydrateFallbackを忘れずに定義しましょう。定義を忘れるとSSR時にuseLoaderDataから取得したデータはloaderのデータになりますので注意してください。