Next.js App Routerにて、サーバー側でfetchした値をReactのContextに渡す方法の覚書
データの取得はサーバー側で1度だけ行いたいが、取得した値はクライアントで参照したい場合のケースについてのメモがあります。APIの呼び出しもクライアント側で行う場合と、サーバー側でキャッシュする場合の2つのコード例が紹介されています。サーバー側でAPI取得をする方法については、propsを使ってコンポーネントに渡すことができることが示されています。また、開発コンソールのネットワークタブでもリクエストは出ていないことが確認できました。
広告ここから
広告ここまで
目次
「データの取得は、サーバー側で1度だけ行いたい」が、「取得した値はクライアントで参照するので、Contextにいれたい」みたいなケースがあたので調べたメモです。
素直に書くと、多分こうなるかなと思ったコード
クライアント側でやるならば、大体こんな感じになるはずです。
"use client"
import { FC, PropsWithChildren, createContext, useContext, useState, useEffect } from "react";
export const ExampleContext = createContext<{
posts: object[]
}>({
posts: []
})
export const useExampleContext = () => useContext(ExampleContext)
export const ExampleContextProvider: FC<PropsWithChildren<{}>> = ({children}) => {
const [posts, setPosts] = useState([])
useEffect(() => {
fetch('https://example.com/dummy-json-api-path')
.then(data => data.json())
.then(data => setPosts(data))
}, [])
return (
<ExampleContext.Provider
value={{
posts
}}
>
{children}
</ExampleContext.Provider>
)
}
ただしこれだと、API呼び出しもクライアント側です。
microCMSやkintoneなど、API制限もしくはメンテナンス日があるものは、サーバー側でキャッシュしておきたいと思います。
ContextのProviderではpropだけ受け取る
いま試しているのは、こんなコードです。
"use client"
import { FC, PropsWithChildren, createContext, useContext } from "react";
export const ExampleContext = createContext<{
posts: object[]
}>({
posts: []
})
export const useExampleContext = () => useContext(ExampleContext)
export const ExampleContextProvider: FC<PropsWithChildren<{
posts: object[]
}>> = ({posts, children}) => {
return (
<ExampleContext.Provider
value={{
posts
}}
>
{children}
</ExampleContext.Provider>
)
}
posts
をpropsで受け取るようにしました。
あとは親コンポーネント側でfetchしてやるだけです。
import Image from 'next/image'
import { ExampleConsumer, ExampleContext, ExampleContextProvider } from './Context'
export default async function Home() {
const posts = await fetch('https://example.com/dummy-json-api-path').then(data => data.json())
return (
<div>
<h1>Context area</h1>
<ExampleContextProvider
posts={posts}
>
<h2>Inner content</h2>
<ExampleConsumer />
</ExampleContextProvider>
</div>
)
}
これでサーバー側でのAPI取得が実現できた・・・はずです。
開発コンソールの[ネットワーク]タブでも、localhost
以外にリクエストを出している様子はありませんでした。
おわりに
サーバーサイドの処理もまとめて書けるようになった分、慣れるまではサーバー・クライアント間のデータ受け渡しで「どうやるんだっけ・・・?」ってなる予感がします。
ただ、今回のサンプルアプリを作ってみた感触として、「子に渡してしまえばただのpropsやね」と考えるのがいい・・・のかもしれません。