stateとは
-
ユーザーの操作や時間経過などにより変化する値。コンポーネントが持つ可変のデータ。
-
別のコンポーネントから直接参照・更新することはできない。
(別のコンポーネントで扱うには、propsやcontextを使う。) -
stateの状態を管理するにはuseState関数を使う。
useStateの使い方
useStateを利用するためには、useStateをimportする。
import { useState } from 'react';
useStateの宣言
//構文
const [変数名, 関数名] = useState(変数の初期値);
//例
const [count, setCount] = useState(0);
//setCountメソッドを使ってcountの値を変更することができる
この書き方は、JavaScriptの分割代入の構文。
useStateの宣言をすると、useStateからは2つの要素を持つ配列が返される。
1つ目はstateの現在値、2つ目はstateを更新するための関数。
上の例ではcountとsetCountという名前の2つの変数を作り、useStateから返される値のうち1つ目をcountに、2つ目をsetCountに代入する、という意味になる。
使ってみる
ローカルでReactの実行環境は作成済みとする。
参考:React.jsを始めよう:動かしながら仕組みを知ろう
//useStateを使うためのimport
import React, { useState } from "react"
function App() {
//stateの初期値をsountに、stateを更新するための関数をsetCountに代入
const [count, setCount] = useState(0)
//setCountを使ってcountを更新する関数を定義
const increment = () => setCount(count + 1)
const decrement = () => setCount(count - 1)
return (
<div>
<h3>りんごの在庫:{count}個</h3>
<button onClick={increment}>1つ購入</button>
<button onClick={decrement}>1つ食べる</button>
</div>
)
}
export default App
機能追加してみる
りんごの在庫が0個になると、「1つ食べる」ボタンは押せなくなり、エラーメッセージが表示されるようにしてみる。
import React, { useState } from "react"
function App() {
const [count, setCount] = useState(0)
//countが0以下のときtrue、1以上であればfalseになる、disabledを定義
const disabled = count<=0
const increment = () =>setCount(count + 1)
const decrement = () =>setCount(count - 1)
return (
<div style={{ margin: "50px" }}>
<h3>りんごの在庫:{count}個</h3>
<button onClick={increment}>1つ購入</button>
{//disabledがtrueのとき、HTMLのdisable属性を有効にする}
<button disabled={disabled} onClick={decrement}>1つ食べる</button>
{count <= 0 &&
<h4 style={{ color: "red" }}>
りんごを食べ切ったよ!!
</h4>
}
</div>
);
}
export default App
state更新のタイミング
ただしuseStateを使って値を更新しても、即時にstateの値が変わるわけでは無い。
動きを知るため、先ほどのApp.jsにアラートとコンソール への出力を書き足してみる。
import React, { useState } from "react";
const App = () => {
console.log("App");
const [count, setCount] = useState(0);
const disabled = count <= 0;
const increment = () => {
setCount(count + 1);
alert(`りんごが${count}個になったよ!`); //追記
};
const decrement = () => setCount(count - 1);
console.log(`りんごは今${count}個`); //追記
return (
<div style={{ margin: "50px" }}>
<h3>りんごの在庫:{count}個</h3>
<button onClick={increment}>1つ購入</button>
<button disabled={disabled} onClick={decrement}>
1つ食べる
</button>
{count <= 0 && <h4 style={{ color: "red" }}>りんごを食べ切ったよ!!</h4>}
</div>
);
};
export default App;
するとアラート時点ではstateの値が更新されておらず、コンソール に表示されるときにはstateの値が更新されている。
更新した後の値を即時に使いたい場合は、useStateで扱うstateをそのまま使うのではなく、更新した値を別の変数として定義する。
const increment = () => {
const newCount = count + 1;
setCount(newCount);
alert(`りんごがcount:${count}個、newCount:${newCount}になったよ!`);
};
以下のように関数を切り分けたとすると…
const increment = () => {
const newCount = count + 1;
setCount(newCount);
alertCount(newCount);
};
const alertCount = (newCount) => {
alert(`りんごがcount:${count}個、newCount:${newCount}個になったよ!`);
};
やはりstateはalertCountを呼び出す時点では更新されていないことがわかる。
さいごに
useStateの特徴
- ページをリロードするとstateはリセットされる(初期値になる)
- stateが更新されるごとに、コンポーネントは再レンダリングされる
レンダリングとは
stateやpropsの変更差分を反映したDOMを再構築すること。
レンダリングが起きると、コンポーネントの頭から処理が順に行われる。
参考記事