🧰

ReactからSolidに変えました

2022/06/07に公開

趣味でプログラミングをしていて、ライブラリをReactからSolidに変えたので、変えるときに気をつけたことを書きます。

クラスコンポーネントを関数コンポーネントにする

Solidにはクラスコンポーネントがないので、関数コンポーネントに書きなおします。

フック関数を変える

ReactとSolidはフック関数が違うので、書きなおします。

useStatecreateSignal

戻り値の一つ目が関数になっているので、気をつけます。

// 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);

useEffectcreateEffect , onCleanup

二つ目の引数がなくなっています。中で使ったシグナルで自動で依存関係を作るらしいです。
また、関数の戻り値が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>
</>

classNameclass

SolidではHTMLと同じ class を使います。

// React
<span className="class1"></span>

// Solid
<span class="class1"></span>

おわりに

Solidにしたら、Reactの時よりもファイルサイズが小さくなって、ページ表示も速くなったのでよかったです。
皆さんもぜひSolidを使ってみてください。

https://www.solidjs.com/

Discussion