Open2

Next.js v13 で遭遇したエラー達

manaki ikedammanaki ikedam

エラー

クライエント側で use を使うと再レンダリングが何度も走ってしまう。

app/player/page.tsx
"use client"

import React, { use } from "react"

const getPlayer = async () => {
  const res = await fetch("http://localhost:3000/api/mock/player")
  if (!res.ok) {
    throw new Error("プレイヤーの取得に失敗しました。")
  }
  return res.json()
}

// このコンポーネントが無限に再レンダリングされる
const Player = () => {
  console.log("レンダリング(`・ω・´)")
  const data = use(getPlayer())
  return (
    <div>
      <p>{data?.player.name}</p>
      <p>{data?.player.bio}</p>
    </div>
  )
}

const PlayerPage = () => {
  return (
    <div>
      <h1>プレイヤーのページ</h1>
      <Player />
    </div>
  )
}

export default PlayerPage

原因

use にはキャッシュの責務がない事が原因で、Promise 解決 -> レンダリング -> Promise 解決のループが無限に発生してしまうらしい。

解決策

cache という関数の実行結果をメモ化する hook を利用する事で、引数が変わるまで getPlayer が同じ promise を返し、再レンダリングを抑止できる。

...
import { use , cache } from "React"

const getPlayer = cache(async () => {
  const res = await fetch("http://localhost:3000/api/mock/player")
  if (!res.ok) {
    throw new Error("プレイヤーの取得に失敗しました。")
  }
  return res.json()
})
...

参考にさせていただいた記事

https://github.com/reactjs/rfcs/blob/9c21ca1a8e39d19338ba750ee3ff6f6c0724a51c/text/0000-first-class-support-for-promises.md

https://zenn.dev/uhyo/articles/react-use-rfc

https://zenn.dev/nishiurahiroki/articles/7e61590892499b

https://beta.nextjs.org/docs/data-fetching/caching

manaki ikedammanaki ikedam

エラー

use と cache と Suspense を組み合わせて使うと Error: Not implemented. が表示される。

app/player/page.tsx
"use client"
...
const PlayerPage = () => {
  return (
    <div>
      <h1>プレイヤーのページ</h1>
+      <Suspense fallback={<div>loading!!</div>}>
         <Player />
+      </Suspense>
    </div>
  )
}
...

原因

cache の一部の機能 (getCacheForType) がまだ未実装な為エラーが起きるらしい。
Suspense を使った際に呼びされる?

https://github.com/facebook/react/blob/8e2bde6f2751aa6335f3cef488c05c3ea08e074a/packages/react-server/src/ReactFizzCache.js

Hi friends! Really appreciate all the investigation and discussion here. I spoke with the team about this and >it looks like, perhaps as expected, we don't have this functionality quite finished yet. We tried to clarify in >the docs that fetch is not yet supported in client components - the recommendation right now is to fetch >data in server components.

Next.js 公式的には fetch はクライアントコンポネントに未対応のため、サーバーコンポーネントでのデータの取得を推奨しているらしい。

fetch is currently not supported in Client Components and may trigger multiple re-renders. For now, if you >need to fetch data in a Client Component, we recommend using a third-party library such as SWR or React >Query.

beta next.js ドキュメントにも記載があり、クライアントコンポーネントで fetch したい場合は、SWR か React Query を使う事を推奨しているらしい。

解決策

データの取得はなるべく、サーバー側で行って、use, cache, fetch の代わりに SWR, axios? を使うほうが良さそう?
Suspense を使わなければ、エラーは起きなくなった。

参考にさせていただいた記事

https://zenn.dev/ojin/articles/8b383b0ac98eb9

https://beta.nextjs.org/docs/data-fetching/fetching#use-in-client-components

https://github.com/vercel/next.js/issues/42180#issuecomment-1304493899