ReactからSolidに変えました
趣味でプログラミングをしていて、ライブラリをReactからSolidに変えたので、変えるときに気をつけたことを書きます。
クラスコンポーネントを関数コンポーネントにする
Solidにはクラスコンポーネントがないので、関数コンポーネントに書きなおします。
フック関数を変える
ReactとSolidはフック関数が違うので、書きなおします。
useState
→ createSignal
戻り値の1つ目が関数になっているので、気をつけます。
// React
function useState(initialState: T): [T, (state: T) => void];
const [state, setState] = useState(initial);
// Solid
function createSignal(value: T): [() => T, (state: T) => T];
const [state, setState] = createSignal(initial);
useEffect
→ createEffect
, onCleanup
2つ目の引数がなくなっています。中で使ったシグナルによって自動で依存関係を作るらしいです。
また、関数の戻り値がReactでは次に呼ばれるときの前に実行するクリーンアップ関数でしたが、Solidでは次に関数が呼ばれるときの引数を戻り値にします。
クリーンアップ関数を作りたいときは onCleanup
を使います。
// React
function useEffect(effect: () => void | Destructor, deps?: unknown[]): void;
useEffect(() => {
const hoge = getHoge(fuga);
return () => {
cleanHoge(hoge);
};
}, [fuga]);
// Solid
function createEffect(effect: (p: Prev) => Next): void;
createEffect(() => {
const hoge = getHoge(fuga());
onCleanup(() => {
cleanHoge(hoge);
});
});
useRef
→ なし
Solidはコンポーネント関数を最初の1回しか実行しないので、宣言した値が再レンダリングの時に変わることはありません。JSXの ref
に渡すときも、変数をそのまま代入して使えます。
// React
const divRef = useRef();
<div ref={divRef}></div>;
// Solid
let divRef;
<div ref={divRef}></div>;
リアクティブにする
Solidはコンポーネント関数を最初の1回しか実行しません。なのでコンポーネントの中でシグナルを使った計算値や関数呼び出しをそのまま書いても値が変化しなかったり、1回しか実行されなかったりしてリアクティブではなくなります。リアクティブのために、値はそれを返す関数にして、関数呼び出しはエフェクトの中で行うようにします。
// React
const [count, setCount] = useState(0);
// 計算値
const doubleCount = count * 2;
// 関数呼び出し
console.log("double count is " + doubleCount + ".");
<button onclick={() => setCount((v) => v + 1)}>click</button>;
// Solid
const [count, setCount] = createSignal(0);
const doubleCount = () => count() * 2;
createEffect(() => {
console.log("double count is " + doubleCount() + ".");
});
<button onclick={() => setCount((v) => v + 1)}>click</button>;
JSXのループや分岐に特別なコンポーネントを使う
Solidにはループや条件分岐をする特別なコンポーネントがあるので、それを使います。
// React
<>
{isTrue ? "hello" : 42}
{array.map(value => <span>{value.toString()}</span>)}
</>
// Solid
<>
<Show when={isTrue()} fallback={42}>
hello
</Show>
<For each={array()}>
{value => <span>{value.toString()}</span>}
</For>
</>
props
のデストラクチャをなくす
Solidはリアクティブのために props
のプロパティアクセスをゲッター関数にしています。しかし、デストラクチャをすると関数からただの値になってしまい、リアクティブではなくなります。
もし props
を分割したい場合は splitProps
関数、デフォルトの props
を使いたい場合は mergeProps
関数を使います。
props = mergeProps({ children: "default children" }, props);
const [local, others] = splitProps(props, ["children"]);
<>
<Child {...others} />
<div>{local.children}<div>
</>
className
→ class
SolidではHTMLと同じ class
を使います。
// React
<span className="class1"></span>
// Solid
<span class="class1"></span>
おわりに
Solidにしたら、Reactの時よりもファイルサイズが小さくなって、ページ表示も速くなったのでよかったです。
皆さんもぜひSolidを使ってみてください。
Discussion