preactのsignalsのドキュメントとソースコードを少し読んだ
これを読みました。
signalによる最適化
今までuseStateで書いていた部分をsignal()と書くことで状態管理を行えます。signalには.value
というプロパティがあり、この.value
が更新される時だけ再レンダリングが走る仕組みになっています。setState的なのは、内部的にはこのあたりでやってます
つまりpropsで渡ってきた時などでは、参照のみになるため再レンダリングが走らないようです。(useStateだと毎回再レンダリングされる)
値更新時に、現在の値を同じ値を代入してもsignal自体は更新されません。
以下ベーシックな記述を公式からそのまま拝借
import { signal } from "@preact/signals";
// Create a signal that can be subscribed to:
const count = signal(0);
function Counter() {
// Accessing .value in a component automatically re-renders when it changes:
const value = count.value;
const increment = () => {
// A signal is updated by assigning to the `.value` property:
count.value++;
}
return (
<div>
<p>Count: {value}</p>
<button onClick={increment}>click me</button>
</div>
);
}
API
状態管理系で必要そうなAPIは、以下のように揃っていそうです。
- 他のsignalを元に計算して、新しいsignalを作るときは
computed()
を使用できます。 - signalが変更した時に何か処理をしたいときは、
effect()
を使用できます。(useEffectと似ていますが若干違いそう。) - 複数の値の更新を1つにまとめて行う関数として、
batch(() => {})
が使用できます。
また、signalは、セッターを叩けば値が更新される仕様上、グローバルな状態管理(useContextみたいな使い方)として使用できます。なのでコンポーネントだけに状態を、閉じたい場合はuseSignal()
のようなHookが用意されています。内部実装的には、coreに各種APIのビジネスロジックがあり、preactとreactそれぞれHooksとして提供できるように、別ファイルに切り分けられていました。
https://github.com/preactjs/signals/tree/main/packages
実は、Reactでも使用できるんですね。。。
感想
やっぱり値の更新の記述が、一番気になる感じでしょうか。useStateだとset関数を必ず使うことで、なんとなく分かりやすかったですが、signalの場合は.value
に代入する書き方になるので慣れるかどうかです。ただ今までも、オブジェクトや配列の一部の値を更新したい時は、useStateで似たような書き方はしていたので、あまり気にならないかも。
グローバルなsignalだけちょっと怖さもあるのですが、個人的には、結構良いなと思いました。
後実際のソースコードの量がかなりシンプルなので、読むだけでお勉強になりました。