Open5

solidjsメモ

tomyam2020tomyam2020
  • solidjsではreactのstaetに該当するものにsignalがある。createSignalで宣言。値を取得するときは関数形式で実行する
  • reactのuseEffectに該当するものにcreateEffectがある。これはコールバック内にあるsignalが更新されると自動的に呼び出される

SolidJSとReactの違い:実例で見る主要な相違点

SolidJSとReactは、どちらもモダンなUI開発のためのJavaScriptライブラリですが、いくつかの重要な違いがあります。この記事では、実例を交えながらこれらの違いを探っていきます。

1. 状態管理:Signal vs State

ReactではuseStateフックを使用して状態を管理しますが、SolidJSではcreateSignalを使用します。

React例:

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

SolidJS例:

import { createSignal } from 'solid-js';

function Counter() {
  const [count, setCount] = createSignal(0);

  return (
    <div>
      <p>Count: {count()}</p>
      <button onClick={() => setCount(count() + 1)}>Increment</button>
    </div>
  );
}

注目すべき点は、SolidJSでは値を取得する際に関数形式で呼び出す(count())必要があることです。これにより、SolidJSは値の変更を正確に追跡し、必要な部分のみを効率的に更新できます。

2. 副作用:useEffect vs createEffect

ReactのuseEffectに相当するものが、SolidJSではcreateEffectです。

React例:

import React, { useState, useEffect } from 'react';

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds(s => s + 1);
    }, 1000);

    return () => clearInterval(interval);
  }, []);

  return <div>Seconds: {seconds}</div>;
}

SolidJS例:

import { createSignal, createEffect } from 'solid-js';

function Timer() {
  const [seconds, setSeconds] = createSignal(0);

  createEffect(() => {
    const interval = setInterval(() => {
      setSeconds(s => s + 1);
    }, 1000);

    return () => clearInterval(interval);
  });

  return <div>Seconds: {seconds()}</div>;
}

SolidJSのcreateEffectは、コールバック内で使用されているシグナルが更新されると自動的に再実行されます。ReactのuseEffectとは異なり、依存配列を指定する必要がありません。

主な違いのまとめ

  1. 状態管理:

    • React: useState
    • SolidJS: createSignal(値の取得時に関数呼び出しが必要)
  2. 副作用:

    • React: useEffect(依存配列の指定が必要)
    • SolidJS: createEffect(自動的に依存関係を追跡)
  3. レンダリング:

    • React: 仮想DOMを使用
    • SolidJS: 細粒度のリアクティビティを使用し、直接DOMを更新
  4. パフォーマンス:

    • SolidJSは一般的にReactよりも高速とされています。これは、仮想DOMを使用せず、必要な部分のみを更新するためです。
  5. 学習曲線:

    • ReactユーザーにとってSolidJSは比較的学びやすいですが、いくつかの概念の違いに注意が必要です。

SolidJSはReactの良い部分を取り入れつつ、独自の最適化アプローチを採用しています。どちらを選択するかは、プロジェクトの要件やチームの経験によって異なりますが、SolidJSは特にパフォーマンスが重要なアプリケーションで注目を集めています。

Citations:
[1] https://qiita.com/shadowTanaka/items/b6d00863a8d6bff37de6
[2] https://cohamu.com/entry/20240514/1715650200
[3] https://www.codegrid.net/articles/2022-solidjs-1/
[4] https://qiita.com/tonio0720/items/c28b4d37e6ab860ea04d
[5] https://engineering.monstar-lab.com/jp/post/2022/05/30/Similar-To-React-But-Efficient-Solid/

tomyam2020tomyam2020

シグナルに基づいた値を返す関数と思っておけばよい

派生シグナル
シグナルを参照する関数は依存しているシグナルが更新されると自動的に再実行される。

SolidJSのderived signal(派生シグナル)は、1つ以上の基本シグナルに基づいて計算された値を提供する強力な機能です。以下にderived signalの主な特徴と使用方法を解説します:

  1. 定義と基本概念:
    Derived signalは、他のシグナルの値を使用して計算される関数です。基本シグナルが変更されると、derived signalも自動的に更新されます[1][5]。

  2. 使用方法:

import { createSignal } from 'solid-js';

const [count, setCount] = createSignal(0);
const double = () => count() * 2;

この例では、doubleがderived signalとなります[5]。

  1. 特徴:
  • 遅延評価: Derived signalは必要になるまで計算されません。
  • 自動更新: 依存するシグナルが変更されると自動的に再計算されます。
  • 値の保持なし: 自身で値を保持せず、必要時に計算します[5]。
  1. 用途:
  • 複数のシグナルを組み合わせた計算
  • UIの一部を更新する際の条件や値の提供
  • コードの可読性向上とロジックの集約[1]
  1. Effectsとの違い:
  • Derived signalsは値の合成に使用され、副作用を持ちません。
  • Effectsは副作用を生成し、シグナルの変更に反応します[3]。
  1. パフォーマンス:
    Derived signalsは必要な時のみ再計算されるため、パフォーマンスの最適化に役立ちます。

  2. 例:

const [firstName, setFirstName] = createSignal("John");
const [lastName, setLastName] = createSignal("Doe");
const fullName = () => `${firstName()} ${lastName()}`;

この例では、fullNameがderived signalとなり、firstNameまたはlastNameが変更されると自動的に更新されます[1]。

Derived signalsは、SolidJSの反応性システムの重要な部分であり、複雑な状態管理を簡素化し、アプリケーションの効率を向上させるのに役立ちます。

Citations:
[1] https://egghead.io/blog/manage-reactive-state-with-solidjs-signals
[2] https://www.solidjs.com/tutorial/introduction_derived
[3] https://www.reddit.com/r/solidjs/comments/udu5vi/effects_vs_derived_signals/?rdt=37234
[4] https://www.youtube.com/watch?v=VbHsnetYrRU
[5] https://docs.solidjs.com/concepts/derived-values/derived-signals

tomyam2020tomyam2020

Forコンポーネント

仮想DOMがない場合にArray.prototype.mapを単純に使用すると全てのDOM要素が再作成される理由は、JavaScriptの実行モデルとDOMの更新の仕組みに関係しています。

  1. 直接DOMを操作する場合:

仮想DOMを使用しないフレームワークでは、コンポーネントの再レンダリング時に直接DOMを操作します。Array.prototype.mapを使用すると、以下のような処理が行われます:

  1. 既存のDOM要素がすべて削除されます。
  2. mapによって新しい要素の配列が生成されます。
  3. 生成された新しい要素がDOMに挿入されます。

この方法では、データに変更がない要素も含めて全てのDOM要素が再作成されるため、パフォーマンスの低下につながります[1][2].

  1. 仮想DOMを使用する場合:

対照的に、ReactのようなフレームワークでArray.prototype.mapを使用しても問題が生じないのは、仮想DOMの差分検出(Diffing)アルゴリズムのおかげです。仮想DOMは:

  1. 新しい仮想DOMツリーを生成します。
  2. 前回のレンダリング結果と比較し、実際に変更された部分のみを特定します。
  3. 変更された部分のみ実際のDOMを更新します。

このプロセスにより、不要なDOM操作を最小限に抑えることができます[1][2].

  1. SolidJSのアプローチ:

SolidJSは仮想DOMを使用せず、代わりに細粒度のリアクティビティを採用しています。テンプレートヘルパー(For、Show、Switchなど)を使用することで:

  1. 配列の各要素に対して個別のリアクティブな計算を設定します。
  2. 配列の変更があった場合、影響を受ける要素のみを更新します。
  3. 変更のない要素は再レンダリングされません。

このアプローチにより、仮想DOMを使用せずに効率的な更新を実現しています[1][2][4].

結論として、SolidJSのテンプレートヘルパーは、仮想DOMの利点(効率的な更新)を得つつ、仮想DOMのオーバーヘッドを避けるための解決策として機能しています。これにより、高いパフォーマンスと効率的なDOM更新を両立しています。

Citations:
[1] https://zenn.dev/jay_es/articles/2021-07-24-solidjs
[2] https://qiita.com/tonio0720/items/ad2c33d9bea57435f5ea
[3] https://zenn.dev/7oh/scraps/ca08dd983fd3c9
[4] https://www.codegrid.net/articles/2022-solidjs-1/
[5] https://www.ey-office.com/blog_archive/2022/06/23/tried-to-get-started-with-the-topic-solidjs-2/

tomyam2020tomyam2020

SolidJSのForとIndexコンポーネントの主な違いは、以下のとおりです:

  1. 使用ケース:
  • For: オブジェクトの配列を扱う場合に最適です[1][4]。
  • Index: プリミティブ値(文字列、数値など)の配列を扱う場合に推奨されます[2]。
  1. レンダリング動作:
  • For: 配列の要素が変更された場合、その要素のみを更新または移動します[1][4]。
  • Index: インデックスが変更された場合にのみ再レンダリングします[1]。
  1. パフォーマンス:
  • For: 配列の要素が変更された場合、効率的に DOM を更新します[1][4]。
  • Index: 特定の状況下では For よりも再レンダリングが少なくなる可能性があります[1]。
  1. コールバック関数の引数:
  • For: (item, index) => ... の形式で、item は値そのもの、index は Signal です[3]。
  • Index: (item, index) => ... の形式で、item は Signal、index は数値です[1][3]。
  1. キーの扱い:
  • For: 通常、各要素に一意のキーを指定します(Reactの key プロップに相当)[3]。
  • Index: インデックスをキーとして使用する場合に適しています[3]。

使い分けの目安として、Reactでの経験を持つ開発者であれば、以下のように考えるとよいでしょう:

  • Reactで配列のmapを使用し、keyに要素のIDを指定する場合は、SolidJSではForを使用します。
  • Reactで配列のmapを使用し、keyにインデックスを指定する場合は、SolidJSではIndexを使用します[3]。

これらの違いを理解し、適切に使い分けることで、SolidJSアプリケーションのパフォーマンスと開発効率を向上させることができます。

Citations:
[1] https://dev.to/lico/solidjs-differences-for-and-index-24p9
[2] https://dev.classmethod.jp/articles/solidjs-tutorial-for-index-difference/
[3] https://qiita.com/tonio0720/items/ad2c33d9bea57435f5ea
[4] https://www.solidjs.com/tutorial/flow_for
[5] https://zenn.dev/7oh/scraps/ca08dd983fd3c9

tomyam2020tomyam2020

createEffect と onMount の違い

どちらもコンポーネントのレンダリング後に実行される。違いとしては、createEffectはコールバック内にあるシグナルが更新されると再度コールバックが実行されるが、onMountは確実に一度のみ実行される

onMount は単なるcreateEffect の呼び出しで、非追跡、つまり再実行されません。これは単なる Effect の呼び出しですが、最初のレンダリングがすべて完了した後、コンポーネントに対して一度だけ実行されることを確信して使用できます。