LoginSignup
1
0

Next.jsで、useEffectを使って無限ループを回避する

Posted at

この記事で分かること

  • useStateを使った無限ループの原因
  • useEffectの必要性

対象

  • react, next.js初心者

環境

rocal環境にNext.jsを構築
test.jsを src/pages ディレクトリ配下に作成
laravelで、テスト用に現時刻を返すapiを作成

本題

テスト用のapi

Route::get('/test', function () {
    return ['date' => now()];
});

非同期処理

import React, { useState } from 'react';

export default function Test() {
  const [data, setData] = useState(null);

  // 無限ループの発生
  fetch('http://localhost:80/api/test')
    .then(response => response.json())
    .then((data) => {
        console.log(data.date);
        setData(data.date);
    });

  return (
    <div>
      {data ? data : "Loading..."}
    </div>
  );
}

consoleを見てみると
image.png
無限ループが発生していますね。。

原因

無限ループが発生するのは、fetch関数 がコンポーネントの描画毎に呼び出され、setData によってコンポーネントの状態が更新され、それがさらなる再描画を引き起こすからです。再描画時に再度 fetch が呼び出され、無限ループが発生します。

解決法

無限ループを防ぐためには、useEffect フックを使うのが一般的です。useEffect フックは、コンポーネントのライフサイクルに関連する副作用(API リクエストなど)を処理するために React によって提供されています。

import { useState, useEffect } from 'react';

export default function Test() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch('http://localhost:80/api/test')
      .then(response => response.json())
      .then((data) => {
          console.log(data.name);
          setData(data.name);
      });
  }, []); // 依存配列が空なので、この副作用はコンポーネントがマウントされたときにのみ実行されます

  return (
    <div>
      {data ? data : "Loading..."}
    </div>
  );
}

state 更新の回避

react公式ドキュメントによれば、「現在値と同じ値で更新を行った場合、React は子のレンダーや副作用の実行を回避して処理を終了します。」「更新の回避が起きる前に React により該当のコンポーネント自体はレンダーされるかもしれない、ということに注意してください。」と記述されていました。

今回のTest function の例では、fetchで取得するdataの値が毎回変わるので、state の更新は回避されません。
もし、値が毎回変わらなければ、更新は回避され、無限ループは発生しませんでした。
しかし、同様のコードを src/pages/_app.js (全ページで呼び出されるコンポーネント) に配置したとき、無限ループが発生したので、どのディレクトリでも、推奨されるuseEffectの使用をするのが良いでしょう。

1
0
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
1
0