とりあえずやってみよう!
とりあえずクリックしたらfoo
が1ずつ増える関数を書いてみる。
export default function Home() {
let foo = 1;
const handleClick = () => {
foo = foo + 1;
console.log(foo);
};
return (
<>
<h1>{foo}</h1>
<button
onClick={handleClick}>
ボタン
</button>
</>
)
}
しかしこのコードだけではブラウザの数字がずっと「1」のままになってしまう。
コンソールはしっかりと1ずつ増えているのに、、、
その原因は再レンダリング!!!
Reactにおいて画面の表示を変えるには「再レンダリング」がされなくてはならない。
しかしそれにはいくつか条件がある。
①ページ遷移したとき
②データの変更(カウンターのように、単にクライアントサイドだけで変更されたときはダメ)
③コンテキストの変更
④getStaticPropsまたはgetServerSidePropsの呼び出し
など。
条件に当てはまればブラウザの数字も変わる!
もっと詳しくいうと
ボタンを何回もクリックするとfoo
の値はもちろん変わっている。
しかしReactは変数の変化だけだと、変わったことを認識しない!
そのためHomeコンポーネントが2回目以降のレンダリングがされないので、一番初めの「1」になったままということ。
「Homeコンポーネントがもう一回呼び出される = 再レンダリング」ということなので、再レンダリングがされる条件に当てはめなければならない。
ここで登場 useState!
import { useState } from 'react';
export default function Home() {
const [foo, setFoo] = useState(1);
const handleClick = () => {
setFoo(foo => foo + 1);
};
return (
<>
<h1>{foo}</h1>
<button
onClick={handleClick}>
ボタン
</button>
</>
)
}
まず[foo, setFoo] = useState(1)
について解説。
言葉にすると次のようになる。[状態を持った変数, 関数] = useState(初期値)
fooが状態を持った変数なので、fooが変わったら再レンダリングされる。←ここ大事だよ!
よって初期値を0にすると状態が変更されないので、console.log
は一度しか表示されない。
つまり再レンダリングされていないのだ。
export default function Home() {
const [foo, setFoo] = useState(1);
const handleClick = () => {
//初期値に注目!
setFoo(foo => foo + 0);
};
//ここに注目!これはHomeコンポーネントが呼び出されないと実行されないよ!
//だから再レンダリングされないと「ボタン」をいくら押しても一度しか表示されないよ!
console.log(foo);
return (
<>
<h1>{foo}</h1>
<button
onClick={handleClick}>
ボタン
</button>
</>
)
}
※ちなみに、
foo + 1
ではなくfoo => foo + 1
の理由は、引数fooを用意することにより、
前回の状態をしっかり反映させることができるため。
仮に2ずつ増やしたくてfoo + 1
を2行書いても、fooに入る数値は一緒なので1ずつしか増やせない。
分割配列について
[foo, setFoo]
の部分は分割配列。
useState()には2つの返り値が存在しているため、
通常であれば返り値を別の変数に入れて変数[0]
、変数[1]
と指定して取り出す。
それがめんどくさいので[foo, setFoo]
を用意してそれぞれに突っ込んじゃおうという策略。