【入門編】 propsからstateへの同期とuseEffectの是非 – React実践ガイド

こんにちは。フロントエンドの世界へようこそ。
Reactを触り始めたばかりの頃、「親から受け取ったデータが変わったのに、画面の表示が変わらない!」と焦って、`useEffect`の中に`setState`を書き込んでしまった経験はありませんか?

実はそれ、多くのエンジニアが一度は通る「Reactの沼」なんです。今日は、この「props(親からのデータ)をstate(自分のデータ)に同期させる」というテーマについて、現場の泥臭い知見を交えながら、優しく紐解いていきましょう。

—

「propsをstateに同期させる」って、どういうこと?

例えば、あなたがカフェの店員さんだと想像してください。
オーナー(親コンポーネント)から「今日のおすすめメニューは『カフェラテ』だよ」とメモ(props)を渡されたとします。あなたはそれを見て、自分の手元のノート(state)に「おすすめ:カフェラテ」と書き込みますよね。

ここまでは良いんです。でも、もしオーナーが途中で「あ、ごめん。今日のおすすめは『アイスティー』に変更ね!」とメモを書き換えたらどうでしょう?

ここで多くの人がやりがちなのが、「メモが書き換わったことに気づくたびに、自分のノートを必死に書き直そうとする」という行動です。これが`useEffect`で`props`を`setState`してしまう現象の正体です。

なぜこれが「非推奨」なのか?

Reactの世界では、「データの源泉(ソース・オブ・トゥルース)は一つであるべき」という鉄の掟があります。

もし、親からの情報(props)と、自分のノート(state)の両方に同じ情報を持たせると、「あれ? 今どっちが正しいんだっけ?」という情報の食い違いが必ずどこかで発生します。これを「同期ズレ」と呼びます。

「useEffectで同期」がもたらす悲劇

以下のようなコード、書いてしまったことはありませんか?

import { useState, useEffect } from ‘react’;

function MenuBoard({ recommendedItem }) {
// propsを初期値にするのはOK!
const [item, setItem] = useState(recommendedItem);

// 【要注意!】propsが変わるたびにstateを上書きしようとする
useEffect(() => {
setItem(recommendedItem);
}, [recommendedItem]);

return

今日のおすすめは: {item}

;
}

このコードの何が問題か。それは、「余計な再描画(レンダリング)」が発生することです。
1. 親から新しい`recommendedItem`が渡される(1回目のレンダリング)
2. `useEffect`が動く
3. `setItem`でstateが更新される(2回目のレンダリングが走る)

たった一つの情報を表示するだけなのに、画面を2回も描き直しているんです。これはアプリが大きくなればなるほど、動作を重くする原因になります。

—

現場の解決策:そもそも「同期」をやめる

じゃあどうすればいいのか? 答えはシンプルです。「自分でstateを持たない」という選択肢をまず検討してください。

ほとんどの場合、`state`にコピーして保持する必要はありません。親からもらった`props`をそのまま使えばいいのです。

解決策1:propsをそのまま使う(推奨)

function MenuBoard({ recommendedItem }) {
// stateにコピーせず、直接表示する!
// これなら同期ズレも起こらないし、再描画も1回で済みます
return

今日のおすすめは: {recommendedItem}

;
}

解決策2:もし「加工」が必要なら?

「いや、受け取ったデータを元に少し加工したいんだ」という場合もあるでしょう。そんな時は、`state`ではなく「メモ化(useMemo)」を使います。

import { useMemo } from ‘react’;

function MenuBoard({ recommendedItem }) {
// propsを元に計算した「新しい値」を作る
// propsが変わった時だけ再計算されるので効率的!
const processedItem = useMemo(() => {
return `【本日限定】${recommendedItem}`;
}, [recommendedItem]);

return

{processedItem}

;
}

—

それでも「同期」が必要な例外的なケース

もちろん、どうしても「初期値として受け取った後は、自分の判断で中身を変えたい」というケースもあります。例えば、入力フォームの初期値などがそうです。

そんな時は、`key`属性を使ってコンポーネントを「作り直す」というテクニックがあります。

// 親コンポーネント側でkeyを渡す

`key`が変わると、Reactは「あ、これは前のコンポーネントとは別物だ」と判断して、古いコンポーネントを破棄し、新しいコンポーネントを最初から作り直してくれます。これなら、`useEffect`で無理やり同期させるよりもずっと安全で、コードもスッキリします。

—

最後に:つまずくのは「理解しようとしている証拠」です

「useEffectでstateを更新してはいけない」というルールを知ると、最初は「じゃあどうやってデータを連動させるの?」とパニックになるかもしれません。大丈夫、それはあなたがReactの仕組みを真剣に考え始めた証拠です。

まずは、「本当にそのstate、自分で持つ必要がある?」と自分に問いかけてみてください。その問いかけこそが、優れたReactエンジニアへの第一歩です。

泥臭い現場の開発でも、一番美しいコードは「一番シンプルなコード」です。あまり難しく考えすぎず、まずはシンプルに、`props`をそのまま渡すことから始めてみてくださいね!

コメント

タイトルとURLをコピーしました