2022/08/09

[Next.js]client側のみで読み込むcomponent(SSRのエラーを回避)

nextjsreactjsjavascript

概要

Next.jsでSSRをすると読み込みエラーとなってしまう3rdパーティ製のReact系ライブラリの活用方法の備忘録です。

経緯

Next.jsで組織図を表示するのに、react-organizational-chartというライブラリを利用しました。

本家のUsageにある通り以下のような記述をすると、client側では動作するのですが、このコンポーネントをimportしたページを(ブラウザ上でリロードするなどして)サーバー側で描画させるとエラーとなってしまいました。
(読み込み時に、undefineddocumentを利用しようとしていたのが原因のようでした。)

import { Tree, TreeNode } from 'react-organizational-chart';

const ExampleTree = () => (
  <Tree label={<div>Root</div>}>
    <TreeNode label={<div>Child 1</div>}>
      <TreeNode label={<div>Grand Child</div>} />
    </TreeNode>
  </Tree>
);

今回は、next/dynamicを使ったその回避方法となります。

※ 注意点:この方法を使うとサーバーサイドでレンダリングすることはできなくなります。

詳細

step1 コンポーネントの定義

まずはSSRでエラーとなる3rdパーティーのライブラリを含んだコンポーネントを定義します。

import { Tree, TreeNode } from 'react-organizational-chart'

export interface MyTree {
  id: number | string
  name: string
  children: Array<MyTree>
}

const MyTreeNode = ({ node }: { node: MyTree }) => {
  return (
    <TreeNode label={<div>{ node.name }</div>}>
      {node.children.map((item) => {
        return (
          <MyTreeNode key={item.id} node={item}></MyTreeNode>
        )
      })}
    </TreeNode>
  )
}

const MyTreeView = ({ tree }: { tree: MyTree }) => {
  return (
    <Tree label={ <div>{ node.name }</div> }>
      {tree.children.map((item) => {
        return (
          <MyTreeNode
            key={item.id}
            node={item}
            onNodeClick={onNodeClick}
            toggle={toggle}
          ></MyTreeNode>
        )
      })}
    </Tree>
  )
}

export default MyTreeView

step2 next/dynamicを使ったimport

上記のコンポーネントをnext/dynamicを使って、クライアント側だけでimportするようにします。

const MyTreeView = dynamic(() => import('@/components/MyTreeView'), { ssr: false })  // ssr: false のオプションをつけて読み込みます。

const MyTreePage = () => {
  const tree = {
    id: 1,
    name: 'root',
    children: [/* 略 */],
  }
  return (
    <MyTreeView tree={tree}></MyTreeView>
  )
}

export default MyTreeView

こちらの方法で、エラーが起きなくなることを確認しました。

以上です。