LoginSignup
3
2

More than 3 years have passed since last update.

【Next.js】Dynamic Import を使ってSSR回避する方法

Last updated at Posted at 2021-04-04

概要

Next.jsでコードを書いている時にこのようなエラーをみたことがあるのではないでしょうか
Warning XXX did not match. Server: XXX Client XXX
このエラーはサーバーとクライアントでレンダリング結果が異なる場合に起こります。Next.jsはビルド時(SSGの本番環境)またはリクエスト時(SSGの開発環境、SSR)にサーバー側で事前にレンダリング(Pre-rendering)が行われサーバ側でコードが走ります、その後、クライアントで処理が走ります。その時の処理のレンダリング結果が異なる場合には上記のエラーになります
この場合、サーバーとクライアントのレンダリング結果を同じにすればいいのですが、どうしようもない場合があります。その時は、Dynamic Import を使ってSSRを回避してCSRにする方法があります
それでは、現在時刻を取得するプログラムを作成し、このエラーをわざと発生させ説明していきます

本題

現在時刻を取得するプログラム

index.jsx
import { useState } from 'react';

const index = () => {
  const now = new Date();
  const [hour, setHour] = useState(now.getHours());
  const [min, setMin] = useState(now.getMinutes());
  const [sec, setSec] = useState(now.getSeconds());
  setInterval(() => {
    const now = new Date();
    setHour(now.getHours());
    setMin(now.getMinutes());
    setSec(now.getSeconds());
  }, 1000);

  return (
    <div>
      {hour}{min}{sec}</div>
  );
};

export default index;

エラー画面

ezgif.com-gif-maker (13).gif
このように毎回エラーが走るわけではありません。サーバーとクライアントのレンダリングが同じ場合も考えられます(秒数が同じ)
最初に起きたエラーのログは
Warning Text content did not match. Server: 30 Client 31
これは、30秒の時にサーバー側でレンダリングされ31秒の時にクライアント側でレンダリングされたため起こったエラーです。実際に30秒の時にリロードしていることがわかると思います

このプログラムを今から書き換えていきます

エラーを修正したプログラム

Dynamic Import

Dynamic Importを使ってSSR回避しCSRにするプログラムです

index.jsx
import dynamic from 'next/dynamic';

const index = () => {
  const DynamicComponentWithNoSSR = dynamic(() => import('../components/Timer'), {
    ssr: false,
  });

  return <DynamicComponentWithNoSSR />;
};

export default index;

components/Timer.jsx
import { useState } from 'react';

const Timer = () => {
  const now = new Date();
  const [hour, setHour] = useState(now.getHours());
  const [min, setMin] = useState(now.getMinutes());
  const [sec, setSec] = useState(now.getSeconds());
  setInterval(() => {
    const now = new Date();
    setHour(now.getHours());
    setMin(now.getMinutes());
    setSec(now.getSeconds());
  }, 1000);
  return (
    <div>
      {hour}{min}{sec}</div>
  );
};

export default Timer;

これで、何度リロードを押してもエラーが走らないのが確認できると思います
これでTimer.jsx内の処理はクライアントだけの処理になっています

修正後デモ画面

ezgif.com-gif-maker (14).gif

おわりに

何か他の良いやり方知ってる方がいればコメントで教えていただけるとうれしいです

参考

Dynamic Import

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2