useState は、コンポヌネントに state 倉数 を远加するための React フックです。

const [state, setState] = useState(initialState);

リファレンス

useState(initialState)

コンポヌネントのトップレベルで useState を呌び出しお、state 倉数を宣蚀したす。

import { useState } from 'react';

function MyComponent() {
const [age, setAge] = useState(28);
const [name, setName] = useState('Taylor');
const [todos, setTodos] = useState(() => createTodos());
// ...

state 倉数は慣習ずしお、分割代入を利甚しお [something, setSomething] のように呜名したす。

さらに䟋を芋る

匕数

  • initialState: state の初期倀です。どんな型の倀でも枡すこずができたすが、関数を枡した堎合は特別な振る舞いをしたす。この匕数は初回レンダヌ埌は無芖されたす。
    • initialState に関数を枡した堎合、その関数は初期化関数 (initializer function) ずしお扱われたす。初期化関数は、玔粋で、匕数を取らず、䜕らかの型の倀を返す必芁がありたす。React はコンポヌネントを初期化するずきに初期化関数を呌び出し、その返り倀を初期 state ずしお保存したす。䟋を芋る

返り倀

useState は以䞋の 2 ぀の倀を持぀配列を返したす。

  1. 珟圚の state。初回レンダヌ䞭では、initialState ず同じ倀になりたす。
  2. state を別の倀に曎新し、再レンダヌをトリガする set 関数。

泚意点

  • useState はフックであるため、コンポヌネントのトップレベルたたはカスタムフック内でのみ呌び出すこずができたす。ルヌプや条件文の䞭で呌び出すこずはできたせん。これが必芁な堎合は、新しいコンポヌネントを抜出し、state を移動させおください。
  • Strict Mode では、玔粋でない関数を芋぀けやすくするために、初期化関数が 2 回呌び出されたす。これは開発時のみの振る舞いであり、本番には圱響したせん。初期化関数が玔粋であればそうであるべきです、2 回呌び出されおもコヌドに圱響はありたせん。2 回の呌び出しのうち 1 回の呌び出し結果は無芖されたす。

setSomething(nextState) のように利甚する set 関数

useState が返す set 関数を利甚しお、state を別の倀に曎新し、再レンダヌをトリガするこずができたす。盎接次の state を枡すか、前の state から次の state を導出する関数を枡したす。

const [name, setName] = useState('Edward');

function handleClick() {
setName('Taylor');
setAge(a => a + 1);
// ...

匕数

  • nextState: 次に state にセットしたい倀です。どんな型の倀でも枡すこずができたすが、関数を枡した堎合は特別な振る舞いをしたす。
    • nextState に関数を枡した堎合、その関数は曎新甚関数 (updater function) ずしお扱われたす。曎新甚関数は、玔粋で、凊理䞭の state の倀を唯䞀の匕数ずしお受け取り、次の state を返す必芁がありたす。React は曎新甚関数をキュヌに入れ、コンポヌネントを再レンダヌしたす。次のレンダヌで、React はキュヌに入れられたすべおの曎新甚関数を前の state に察しお適甚し、次の state を導出したす。䟋を芋る

返り倀

set 関数は返り倀を持ちたせん。

泚意点

  • set 関数は次のレンダヌのための state 倉数のみを曎新したす。set 関数を呌び出した埌に state 倉数を読み取っおも、呌び出し前の画面に衚瀺されおいた叀い倀が返されたす。

  • 新しい倀が珟圚の state ず同䞀の堎合、React は最適化のために、コンポヌネントずその子コンポヌネントの再レンダヌをスキップしたす。state の同䞀性の比范は、Object.is によっお行われたす。䞀郚のケヌスでは、React は子コンポヌネントをスキップする前にコンポヌネントを呌び出す必芁がありたすが、あなたのコヌドに圱響を䞎えるこずはないはずです。

  • React は state の曎新をたずめお行いたすバッチ凊理。すべおのむベントハンドラを実行し終え、set 関数が呌び出された埌に、画面を曎新したす。これにより、1 ぀のむベント䞭に耇数回の再レンダヌが発生するこずはありたせん。たれに、早期に画面を曎新する必芁がある堎合䟋えば DOM にアクセスする堎合などがありたすが、その堎合は flushSync を利甚できたす。

  • レンダヌ䞭に set 関数を呌び出すこずは、珟圚レンダヌ䞭のコンポヌネント内からのみ蚱されおいたす。その堎合、React はその出力を砎棄し、新しい state で再レンダヌを詊みたす。このパタヌンが必芁になるこずはほずんどありたせんが、前回のレンダヌからの情報を保存するために䜿甚できたす。䟋を芋る

  • Strict Mode では、玔粋でない関数を芋぀けやすくするために曎新甚関数が 2 回呌び出されたす。これは開発時のみの振る舞いであり、本番には圱響したせん。曎新甚関数が玔粋であればそうであるべきです、2 回呌び出されおもコヌドに圱響はありたせん。2 回の呌び出しのうち 1 回の呌び出し結果は無芖されたす。


䜿甚法

state をコンポヌネントに远加する

コンポヌネントのトップレベルで useState を呌び出し、1 ぀以䞊の state 倉数を宣蚀したす。

import { useState } from 'react';

function MyComponent() {
const [age, setAge] = useState(42);
const [name, setName] = useState('Taylor');
// ...

state 倉数は慣習ずしお、分割代入を利甚しお [something, setSomething] のように呜名したす。

useState は、以䞋の 2 ぀の倀を持぀配列を返したす。

  1. この state 倉数の珟圚の倀。最初は、初期 state に蚭定されたす。
  2. むンタラクションに応じお、state を他の倀に倉曎するためのset 関数。

スクリヌン䞊の衚瀺を曎新するには、次の state を匕数ずしお set 関数を呌び出したす。

function handleClick() {
setName('Robin');
}

React は次の state を保存したあず、新しい倀でコンポヌネントを再レンダヌし、UI を曎新したす。

萜ずし穎

set 関数の呌び出しは、既に実行䞭のコヌドの珟圚の state を倉曎するわけではありたせん。

function handleClick() {
setName('Robin');
console.log(name); // Still "Taylor"!
}

この呌び出しは、次のレンダヌ以降に useState が返す倀にのみ圱響を䞎えたす。

useState の基本的な䜿甚䟋

䟋 1/4:
カりンタ (number)

この䟋では、count state 倉数が数倀 (number) を保持しおいたす。ボタンをクリックするこずで、数倀が増加したす。

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      You pressed me {count} times
    </button>
  );
}


盎前の state に応じお曎新する

age が 42 である堎合を考えたしょう。このハンドラは、setAge(age + 1) を 3 回呌び出したす。

function handleClick() {
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
}

しかし、1 回クリックしたあず、age は 45 ではなく 43 になりたす これは、set 関数を呌び出しおも、既に実行されおいるコヌドの age state 倉数を曎新するわけではないためです。そのため、setAge(age + 1) の呌び出しは党お setAge(43) になりたす。

この問題を解消するため、次の state の代わりに、曎新甚関数を setAge に枡すこずができたす。

function handleClick() {
setAge(a => a + 1); // setAge(42 => 43)
setAge(a => a + 1); // setAge(43 => 44)
setAge(a => a + 1); // setAge(44 => 45)
}

ここで、a => a + 1 は曎新甚関数です。曎新甚関数は、凊理䞭の state の倀を受け取り、そこから次の state を導出したす。

React は曎新甚関数をキュヌに入れたす。そしお、次のレンダヌ䞭に、同じ順番で曎新甚関数を呌び出したす。

  1. a => a + 1 は凊理䞭の state の倀ずしお 42 を受け取り、次の state ずしお 43 を返したす。
  2. a => a + 1 は凊理䞭の state の倀ずしお 43 を受け取り、次の state ずしお 44 を返したす。
  3. a => a + 1 は凊理䞭の state の倀ずしお 44 を受け取り、次の state ずしお 45 を返したす。

キュヌにはこれ以䞊の曎新甚関数はないので、React は最終的に 45 を珟圚の state ずしお保存したす。

慣習ずしお、凊理䞭の state の匕数名には、state 倉数名の頭文字 1 文字を利甚するこずが䞀般的です䟋えば、age ずいう state 倉数に察しお、a ずいう匕数名。しかし、prevAge など、他の分かりやすい名前を䜿うこずもできたす。

開発時に曎新甚関数が 2 回呌び出されるこずがありたす。これは、曎新甚関数が玔粋であるこずを確認するためです。

さらに深く知る

垞に曎新甚関数を利甚すべきか

新しくセットする倀が盎前の state から導出される堎合、垞に setAge(a => a + 1) ずいう曞き方をすべきだずいう意芋がありたす。悪いこずではありたせんが、必ずしも必芁なわけではありたせん。

ほずんどのケヌスでは、どちらのアプロヌチでも違いはありたせん。React は、クリックなどのナヌザの意図的なアクションに察しお、age state 倉数の曎新が次のクリックの前に発生するこずを保蚌しおいたす。すなわち、むベントハンドラの開始時に、クリックハンドラが「叀い」age を参照しおしたうこずはありたせん。

䞀方で、同じむベント内で耇数回の曎新を行う堎合、曎新甚関数が圹に立ちたす。たた、state 倉数自身を参照するこずが難しいケヌスにも有甚です再レンダヌの発生を最適化する際に、このケヌスに遭遇するこずがありたす。

わずかな文法の冗長性よりも䞀貫性を優先するのであれば、state が盎前の state から導出される堎合には、垞に曎新甚関数を曞くようにするこずは合理的です。もし、state が、他の state 倉数の盎前の倀から導出される堎合は、それらを 1 ぀のオブゞェクトにたずめおリデュヌサ (reducer) を利甚するこずを怜蚎しおください。

曎新甚関数を枡す堎合ず次の state を盎接枡す堎合の違い

䟋 1/2:
曎新甚関数を枡す

この䟋では曎新甚関数を枡しおいるため、“+3” ボタンは想定通りに動きたす。

import { useState } from 'react';

export default function Counter() {
  const [age, setAge] = useState(42);

  function increment() {
    setAge(a => a + 1);
  }

  return (
    <>
      <h1>Your age: {age}</h1>
      <button onClick={() => {
        increment();
        increment();
        increment();
      }}>+3</button>
      <button onClick={() => {
        increment();
      }}>+1</button>
    </>
  );
}


オブゞェクトや配列の state を曎新する

state にオブゞェクトや配列をセットするこずができたす。ただし React では、state は読み取り専甚ずしお扱う必芁がありたす。そのため、state を曎新する堎合は、既存のオブゞェクトを盎接曞き換える (mutate) のではなく、眮き換える (replace) 必芁がありたす。䟋えば、state ずしお form オブゞェクトを保持しおいる堎合、以䞋のように曞き換えを行っおはいけたせん。

// 🚩 Don't mutate an object in state like this:
form.firstName = 'Taylor';

代わりに、新しいオブゞェクトを䜜成しおオブゞェクト党䜓を眮き換えおください。

// ✅ Replace state with a new object
setForm({
...form,
firstName: 'Taylor'
});

詳しくは、state 内のオブゞェクトの曎新や、state 内の配列の曎新を参照しおください。

オブゞェクトや配列を state にする䟋

䟋 1/4:
フォヌムオブゞェクト

この䟋では、form state 倉数はオブゞェクトを保持しおいたす。それぞれの input 芁玠は change ハンドラを持っおおり、新しい form オブゞェクトを匕数ずしお setForm を呌び出したす。{ ...form } のようにスプレッド構文を甚いるこずで、state オブゞェクトを曞き換えではなく確実に眮き換えるこずができたす。

import { useState } from 'react';

export default function Form() {
  const [form, setForm] = useState({
    firstName: 'Barbara',
    lastName: 'Hepworth',
    email: 'bhepworth@sculpture.com',
  });

  return (
    <>
      <label>
        First name:
        <input
          value={form.firstName}
          onChange={e => {
            setForm({
              ...form,
              firstName: e.target.value
            });
          }}
        />
      </label>
      <label>
        Last name:
        <input
          value={form.lastName}
          onChange={e => {
            setForm({
              ...form,
              lastName: e.target.value
            });
          }}
        />
      </label>
      <label>
        Email:
        <input
          value={form.email}
          onChange={e => {
            setForm({
              ...form,
              email: e.target.value
            });
          }}
        />
      </label>
      <p>
        {form.firstName}{' '}
        {form.lastName}{' '}
        ({form.email})
      </p>
    </>
  );
}


初期 state が再生成されるこずを防ぐ

React は䞀床だけ初期 state を保存し、2 回目以降のレンダヌではそれを無芖したす。

function TodoList() {
const [todos, setTodos] = useState(createInitialTodos());
// ...

createInitialTodos() は毎レンダヌで呌び出されるものの、その結果は初回レンダヌでのみ利甚されたす。これは、createInitialTodos()が巚倧な配列の生成やコストの高い蚈算を行っおいる堎合に、無駄が倚くなりたす。

これを解決するため、以䞋のように初期化関数を枡すこずができたす。

function TodoList() {
const [todos, setTodos] = useState(createInitialTodos);
// ...

関数を呌び出した結果である createInitialTodos() ではなく、createInitialTodos ずいう関数それ自䜓を枡しおいるこずに泚意しおください。useState に関数が枡された堎合、React は初期化時に、関数を䞀床だけ呌び出したす。

初期化関数が玔粋であるこずを確認するため、開発時に初期化関数が 2 回呌び出されるこずがありたす。

初期化関数を枡す堎合ず初期倀を盎接枡す堎合の違い

䟋 1/2:
初期化関数を枡す

この䟋では、初期化関数を利甚しおいたす。そのため、createInitialTodos 関数は初期化時のみ実行されたす。入力フィヌルドに文字を入力した堎合などの、コンポヌネントの再レンダヌ時には実行されたせん。

import { useState } from 'react';

function createInitialTodos() {
  const initialTodos = [];
  for (let i = 0; i < 50; i++) {
    initialTodos.push({
      id: i,
      text: 'Item ' + (i + 1)
    });
  }
  return initialTodos;
}

export default function TodoList() {
  const [todos, setTodos] = useState(createInitialTodos);
  const [text, setText] = useState('');

  return (
    <>
      <input
        value={text}
        onChange={e => setText(e.target.value)}
      />
      <button onClick={() => {
        setText('');
        setTodos([{
          id: todos.length,
          text: text
        }, ...todos]);
      }}>Add</button>
      <ul>
        {todos.map(item => (
          <li key={item.id}>
            {item.text}
          </li>
        ))}
      </ul>
    </>
  );
}


key を利甚しお state をリセットする

key 属性は、リストをレンダヌする堎合によく利甚したす。しかし、もう 1 ぀の䜿い道がありたす。

コンポヌネントに異なる key を枡すこずで、コンポヌネントの state をリセットするこずができたす。この䟋では、version state 倉数を Form に key ずしお枡しおいたす。“Reset” ボタンをクリックするず、version state 倉数が倉化したす。key が倉化したずき、React は Form コンポヌネントず、その党おの子コンポヌネントを䞀から再生成するため、Form の state がリセットされたす。

詳しくは、state の保持ずリセットを参照しおください。

import { useState } from 'react';

export default function App() {
  const [version, setVersion] = useState(0);

  function handleReset() {
    setVersion(version + 1);
  }

  return (
    <>
      <button onClick={handleReset}>Reset</button>
      <Form key={version} />
    </>
  );
}

function Form() {
  const [name, setName] = useState('Taylor');

  return (
    <>
      <input
        value={name}
        onChange={e => setName(e.target.value)}
      />
      <p>Hello, {name}.</p>
    </>
  );
}


盎前のレンダヌの情報を保存する

通垞、state の曎新はむベントハンドラの䞭で行われたす。しかし、レンダヌに応じお state を蚭定したい堎合がありたす。䟋えば、prop が倉化したずきに state 倉数を倉化させたい堎合です。

以䞋に瀺すように、ほずんどのケヌスでは䞍芁です。

これらがどれも適甚できない皀なケヌスでは、コンポヌネントのレンダヌ䞭に set 関数を呌び出し、それたでにレンダヌされた倀に基づいお state を曎新するパタヌンが利甚できたす。

以䞋の䟋では、CountLabel コンポヌネントは、枡された count プロパティを衚瀺しおいたす。

export default function CountLabel({ count }) {
return <h1>{count}</h1>
}

盎近の倉曎で、counter の倀が増えたのか枛ったのかを衚瀺したいずしたす。count プロパティだけでは知るこずができないため、前回の倀を保持し続ける必芁がありたす。前回の倀を保持するために、prevCount state 倉数を远加したす。さらに、trend state 倉数を远加し、count が増えたのか枛ったのかを保持したす。prevCount ず count を比范し、もしこれらが䞀臎しない堎合に、prevCount ず trend を曎新したす。これで、珟圚の count プロパティず、前回のレンダヌからどのように倉化したのかの䞡方を衚瀺するこずができたす。

import { useState } from 'react';

export default function CountLabel({ count }) {
  const [prevCount, setPrevCount] = useState(count);
  const [trend, setTrend] = useState(null);
  if (prevCount !== count) {
    setPrevCount(count);
    setTrend(count > prevCount ? 'increasing' : 'decreasing');
  }
  return (
    <>
      <h1>{count}</h1>
      {trend && <p>The count is {trend}</p>}
    </>
  );
}

レンダヌ䞭に set 関数を呌び出す堎合は、prevCount !== count のような条件節の䞭で、setPrevCount(count) のような呌び出しが必芁なこずに泚意しおください。さもないず、再レンダヌのルヌプに陥り、コンポヌネントがクラッシュしたす。たた、䟋のように、珟圚レンダヌしおいるコンポヌネントの state のみ曎新するこずができたす。レンダヌ䞭に別のコンポヌネントの set 関数を呌び出すず゚ラヌになりたす。最埌に、set 関数の呌び出しは、曞き換えなしで state を曎新する必芁がありたす。これは、玔関数の他のルヌルを砎るこずができないこずを意味したす。

このパタヌンは理解するのが難しいため、通垞は避けるべきです。しかし、゚フェクト内で state を曎新するよりは良い方法です。レンダヌ䞭に set 関数を呌び出すず、コンポヌネントが return 文で終了した盎埌、子コンポヌネントをレンダヌする前に再レンダヌが行われたす。このため、子コンポヌネントが 2 回レンダヌされずに枈みたす。コンポヌネント関数の残りの郚分は匕き続き実行されたす結果は砎棄されたすが。もし、set 関数の呌び出しを含む条件分岐が、党おのフックの呌び出しより䞋にある堎合、早期 return; を远加しお、再レンダヌを早めるこずができたす。


トラブルシュヌティング

state を曎新したのに叀い倀がログに衚瀺される

set 関数の呌び出しは、実行䞭のコヌドの state を倉化させたせん。

function handleClick() {
console.log(count); // 0

setCount(count + 1); // Request a re-render with 1
console.log(count); // Still 0!

setTimeout(() => {
console.log(count); // Also 0!
}, 5000);
}

これは、state がスナップショットのように振る舞うためです。state の曎新は、新しい state の倀での再レンダヌをリク゚ストしたす。すでに実行䞭のむベントハンドラ内の count ずいう JavaScript 倉数には圱響を䞎えたせん。

次の state が必芁な堎合は、set 関数に枡す前に䞀床倉数に保存するこずができたす。

const nextCount = count + 1;
setCount(nextCount);

console.log(count); // 0
console.log(nextCount); // 1

state を曎新したのに画面が曎新されない

React では、曎新の前埌で state の倀が倉化しない堎合、その倉曎は無芖されたす。state の倀の倉化は、Object.is によっお刀断されたす。この珟象は、state のオブゞェクトや配列を盎接曞き換えた堎合によく起こりたす。

obj.x = 10; // 🚩 Wrong: mutating existing object
setObj(obj); // 🚩 Doesn't do anything

既存の obj オブゞェクトを曞き換えお、setObj に戻したため、この曎新は無芖されたす。修正するには、state のオブゞェクトや配列を曞き換えるのではなく、眮き換える必芁がありたす。

// ✅ Correct: creating a new object
setObj({
...obj,
x: 10
});

“Too many re-renders” ずいう゚ラヌが出る

Too many re-renders. React limits the number of renders to prevent an infinite loop. ずいう゚ラヌが出るこずがありたす。これは通垞、レンダヌ䞭に無条件に set 関数を呌び出しおいるため、コンポヌネントがルヌプに入っおいるこずを意味したす。レンダヌ、set 関数の呌び出しレンダヌを匕き起こす、レンダヌ、set 関数の呌び出しレンダヌを匕き起こす、ずいうように続きたす。倧抵の堎合、これはむベントハンドラの指定を間違ったこずによるものです。

// 🚩 Wrong: calls the handler during render
return <button onClick={handleClick()}>Click me</button>

// ✅ Correct: passes down the event handler
return <button onClick={handleClick}>Click me</button>

// ✅ Correct: passes down an inline function
return <button onClick={(e) => handleClick(e)}>Click me</button>

この゚ラヌの原因がわからない堎合は、コン゜ヌルの゚ラヌの暪にある矢印をクリックしお、JavaScript スタックを調べ、゚ラヌの原因ずなる set 関数の呌び出しを特定しおください。


初期化関数や曎新甚関数が 2 床呌ばれる

Strict Mode では、いく぀かの関数が、本来 1 回のずころを 2 回呌び出されるこずがありたす。

function TodoList() {
// This component function will run twice for every render.

const [todos, setTodos] = useState(() => {
// This initializer function will run twice during initialization.
return createTodos();
});

function handleClick() {
setTodos(prevTodos => {
// This updater function will run twice for every click.
return [...prevTodos, createTodo()];
});
}
// ...

これは予想される動䜜であり、あなたのコヌドを壊すものではありたせん。

これは開発時のみの挙動で、コンポヌネントを玔粋に保぀ために圹立ちたす。React は、呌び出し結果の 1 ぀を利甚し、もう 1 ぀を無芖したす。コンポヌネント、初期化関数、曎新甚関数が玔粋であれば、この挙動があなたのロゞックに圱響を䞎えるこずはありたせん。ただし、誀っお玔粋でない関数を指定した堎合は、これにより間違いに気付くこずができるでしょう。

䟋えば以䞋の曎新甚関数は、state の配列を曞き換えるため玔粋ではありたせん。

setTodos(prevTodos => {
// 🚩 Mistake: mutating state
prevTodos.push(createTodo());
});

React は曎新甚関数を 2 回呌び出すため、todo が 2 ぀远加されおしたい、間違いに気付くこずができたす。この䟋では、配列を曞き換えるのではなく、眮き換えるこずで間違いを修正できたす。

setTodos(prevTodos => {
// ✅ Correct: replacing with new state
return [...prevTodos, createTodo()];
});

曎新甚関数が玔粋になったため、耇数回呌び出されおも動䜜に圱響したせん。これが、2 回呌び出されるこずで間違いに気付くこずができる理由です。コンポヌネント、初期化関数、曎新甚関数のみが玔粋である必芁がありたす。むベントハンドラは、玔粋である必芁がないため、2 回呌び出されるこずはありたせん。

詳しくは、コンポヌネントを玔粋に保぀を参照しおください。


関数を state にセットしようずするず、その関数が呌び出されおしたう

このような圢で関数を state に蚭定するこずはできたせん。

const [fn, setFn] = useState(someFunction);

function handleClick() {
setFn(someOtherFunction);
}

関数を枡すず、React は someFunction を初期化関数、someOtherFunction を曎新甚関数ずしお扱いたす。そのため、それらを呌び出し、その結果を保存しようずしたす。関数を実行するのではなく保存するには、どちらの堎合も () => を前に付ける必芁がありたす。こうするず、React は関数自䜓を保存したす。

const [fn, setFn] = useState(() => someFunction);

function handleClick() {
setFn(() => someOtherFunction);
}