ステート
HTML 要素とコンポーネントを作成する方法、そして JSX を使用して props とイベントハンドラーを両方に渡す方法を学んだので、次は仮想 DOM ツリーを更新する方法を学びましょう。
前の章で述べたように、関数コンポーネントとクラスコンポーネントの両方が、その仮想 DOM ツリーを変更するために使用されるコンポーネントによって格納されるデータである **ステート** を持つことができます。コンポーネントがステートを更新すると、Preact は更新されたステート値を使用してそのコンポーネントを再レンダリングします。関数コンポーネントの場合、これは Preact が関数を再呼び出しすることを意味しますが、クラスコンポーネントの場合はクラスの render()
メソッドのみを再呼び出しします。それぞれについて例を見てみましょう。
クラスコンポーネントのステート
クラスコンポーネントには state
プロパティがあり、これは render()
メソッドが呼び出されるときにコンポーネントが使用できるデータを保持するオブジェクトです。コンポーネントは this.setState()
を呼び出して state
プロパティを更新し、Preact による再レンダリングを要求できます。
class MyButton extends Component {
state = { clicked: false }
handleClick = () => {
this.setState({ clicked: true })
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.clicked ? 'Clicked' : 'No clicks yet'}
</button>
)
}
}
ボタンをクリックすると、this.setState()
が呼び出され、これにより Preact がクラスの render()
メソッドを再度呼び出します。this.state.clicked
が true
になったので、render()
メソッドは「まだクリックされていません」の代わりに「クリックされました」というテキストを含む仮想 DOM ツリーを返し、Preact が DOM 内のボタンのテキストを更新します。
フックを使用した関数コンポーネントのステート
関数コンポーネントもステートを持つことができます!クラスコンポーネントのような this.state
プロパティはありませんが、Preact には、関数コンポーネント内でステートを保存および操作するための関数を提供する「フック」と呼ばれる小さなアドオンモジュールが含まれています。
フックは、関数コンポーネント内から呼び出すことができる特別な関数です。それらは、クラスのプロパティやメソッドのように、**レンダリング間で情報を記憶する**ため特別です。たとえば、useState
フックは、値とその値を更新するために呼び出すことができる「セッター」関数を含む配列を返します。コンポーネントが複数回呼び出される(再レンダリングされる)と、コンポーネントが行う useState()
呼び出しは、毎回まったく同じ配列を返します。
ℹ️ フックは実際にはどのように機能するのでしょうか?
舞台裏では、
setState
のようなフック関数は、仮想 DOM ツリー内の各コンポーネントに関連付けられた「スロット」のシーケンスにデータを保存することによって機能します。フック関数を呼び出すと、1つのスロットが消費され、内部の「スロット番号」カウンターが増加して、次の呼び出しで次のスロットが使用されます。Preact は各コンポーネントを呼び出す前にこのカウンターをリセットするため、コンポーネントが複数回レンダリングされると、各フック呼び出しが同じスロットに関連付けられます。function User() { const [name, setName] = useState("Bob") // slot 0 const [age, setAge] = useState(42) // slot 1 const [online, setOnline] = useState(true) // slot 2 }
これは呼び出しサイト順序と呼ばれ、これがフックが常にコンポーネント内で同じ順序で呼び出される必要があり、条件付きで呼び出したり、ループ内で呼び出したりできない理由です。
useState
フックの動作例を見てみましょう
import { useState } from 'preact/hooks'
const MyButton = () => {
const [clicked, setClicked] = useState(false)
const handleClick = () => {
setClicked(true)
}
return (
<button onClick={handleClick}>
{clicked ? 'Clicked' : 'No clicks yet'}
</button>
)
}
ボタンをクリックすると、setClicked(true)
が呼び出され、useState()
呼び出しによって作成されたステートフィールドが更新され、これにより Preact がこのコンポーネントを再レンダリングします。コンポーネントが 2 回目にレンダリング(呼び出し)されると、clicked
ステートフィールドの値は true
になり、返される仮想 DOM は「まだクリックされていません」の代わりに「クリックされました」というテキストになります。これにより、Preact は DOM 内のボタンのテキストを更新します。
試してみましょう!
前の章で作成したコードから始めて、カウンターを作成してみましょう。count
数値をステートに保存し、ボタンがクリックされたときにその値を 1
ずつ増分する必要があります。
前の章では関数コンポーネントを使用したため、フックを使用するのが最も簡単な場合がありますが、どちらのステート保存方法を使用してもかまいません。