0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【WEB】Reactの各種Stateにおける制約違反とエラーの原因まとめ

Posted at

はじめに

React の useStateuseReducer などのState管理には、いくつかの制約が存在します。
これらの制約を破るとエラーが発生し、意図しない動作の原因となります。
私自身も実装中に制約違反でエラーを発生させてしまった為、代表的なStateの制約違反とそのエラーについて、纏めておきたいと思います。

1. useState の制約違反

1-1. State を直接変更してしまう

エラー内容

const [count, setCount] = useState(0);

// 直接変更しようとするとエラーの原因に
count = count + 1; 

エラー原因

  • useState で管理されている変数を直接変更すると、React が状態変更を検知できず、意図しない動作につながる。

正しい実装方法

setCount(count + 1);

または、以下のように関数で実装する

setCount(prevCount => prevCount + 1);

1-2. useState の更新を同期的に期待する

エラー内容

const [count, setCount] = useState(0);

const handleClick = () => {
  setCount(count + 1);
  console.log(count); // 期待通りの値にならない
};

エラー原因

  • useState の更新は非同期で行われるため、setState を実行しても即座には反映されない。

正しい実装方法

const handleClick = () => {
  setCount(prevCount => prevCount + 1);
  console.log(count); // 前の値が表示されるが、Reactの更新後には期待通りに反映される
};

2. useEffect の制約違反

2-1. useEffect の中で setState を適切に管理しない

エラー内容

const [data, setData] = useState(null);

useEffect(() => {
  fetch("/api/data")
    .then(res => res.json())
    .then(json => setData(json)); // `setData` が無限ループを引き起こす可能性あり
}, [data]); // 依存配列が間違っている

エラー原因

  • datauseEffect の依存配列に含めると、setData(json) のたびに useEffect が再実行されてしまい、無限ループになる。

正しい実装方法

useEffect(() => {
  fetch("/api/data")
    .then(res => res.json())
    .then(json => setData(json));
}, []); // 初回のみ実行されるように修正

3. useReducer の制約違反

3-1. Reducer 内で State を直接変更してしまう

エラー内容

const reducer = (state, action) => {
  state.count += 1; // 直接変更
  return state;
};

エラー原因

  • useReducerstate不変(immutable) であるべき。
    • 直接変更すると、React が変更を検知できず、更新が反映されない。

正しい実装方法

const reducer = (state, action) => {
  return { ...state, count: state.count + 1 }; // 新しいオブジェクトを作成
};

4. useRef の制約違反

4-1. useRef を State のように使おうとする

エラー内容

const countRef = useRef(0);

const handleClick = () => {
  countRef.current += 1;
  console.log(countRef.current); // 値は更新されるが、コンポーネントの再レンダリングが発生しない
};

問題点

  • useRef の値は変更できるが、React のレンダリングをトリガーしない
  • useState と違い、値が変更されても UI には反映されない。

正しい実装方法

const [count, setCount] = useState(0);

const handleClick = () => {
  setCount(prevCount => prevCount + 1); // 正しく UI を更新
};

5. useEffect 内で setState を誤ったタイミングで実行

5-1. useEffect 内で setState を条件なしで呼び出す

エラー内容

const [count, setCount] = useState(0);

useEffect(() => {
  setCount(count + 1); // 毎回 `useEffect` が発火 → 無限ループ
}, [count]);

エラー原因

  • setCount(count + 1)useEffect 内で呼ぶと、count の変更によって useEffect が再実行され、無限ループが発生する。

正しい実装方法

useEffect(() => {
  if (count < 5) { // 条件を追加
    setCount(count + 1);
  }
}, [count]);

まとめ

制約違反 原因 解決策
State を直接変更 React が変更を検知できない setState を使って更新
State の更新を同期的に期待 useState は非同期で動作する setState(prev => prev + 1) を使う
useEffect の依存配列ミス 無限ループの原因になる 依存配列を適切に設定
Reducer で State を直接変更 React の不変性ルール違反 return { ...state, newValue }
useRef を State のように使用 useRef はレンダリングをトリガーしない useState を使う
useEffect 内で setState を条件なしで実行 無限ループになる 条件付きで setState を呼ぶ

さいごに

ダイエットが順調に進行中です、減量目標まで50%達成・・・!
健康管理も実装も全力で対応していきますー!

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?