React vs Svelte: Side-by-Side フィーチャ分析
Olivia Novak
Dev Intern · Leapcell

ReactとSvelteフレームワークの比較:レンダリングモードから機能実装まで
Reactと同様に、Svelteはフロントエンドインターフェースを構築するために使用されるリアクティブUIフレームワークであり、開発者はページコードをコンポーネントベースの方法で構成できます。最近、YouTubeでReactとSvelteフレームワークの違いを10個の実用的な例を通して比較するビデオを見ました。その内容は非常に面白く、学習する上で価値があります。したがって、この記事では、ビデオの内容を整理し、私自身の理解を加えて、皆さんの参考になるようにし、これらの2つのフレームワークに対するより深い理解を得るのに役立てます。
比較項目 | React | Svelte |
---|---|---|
レンダリングモード | Virtual DOMを通じて変更が必要なページの部分を計算します。組み込みのRuntimeが必要で、コードサイズが比較的大きいです(たとえば、Next.jsのHello Worldアプリケーションは約70kbのJavaScriptコードです)。 | ビルドプロセス中にコードをコンパイルします。Runtimeの代わりにコンパイラを使用し、最終的な製品にはSvelteライブラリコードが含まれていません。コードサイズは小さいです(たとえば、Hello Worldアプリケーションはわずか3kbです)。 |
state | useState を使用してリアクティブステートとsetter関数を生成します。setterを呼び出すと、UIが再レンダリングされます。 | let で宣言された変数はリアクティブです。変数の値が変更されると、フレームワークは自動的にUIを更新します。 |
props | 関数型コンポーネントでは、プロパティは関数パラメータとして受信され、分割代入がプロパティ値を取得するために一般的に使用されます。プロパティはコンポーネントにすることができます。 | 変数を宣言するときにexport キーワードを追加すると、外部から渡されるプロパティであることを示します。プロパティを渡すための簡略な構文{property name} を提供し、プロパティはコンポーネントにすることはできません。 |
children | props.children を通じて子コンポーネントの情報を取得します。 | スロットslot を通じて実装され、デフォルトスロットと名前付きスロットをサポートします。 |
ライフサイクル | 関数型コンポーネントでは、ライフサイクルはuseEffect を通じてシミュレートされます(たとえば、useEffect で関数を返すことは、コンポーネントのアンマウントに使用されます)。 | onMount やonDestroy などのライフサイクル関数は、script でインポートされます。 |
副作用 | useEffect を通じて副作用を宣言し、副作用が依存する変数を手動で宣言する必要があります。 | $ 記号で始まるリアクティブ式で副作用を宣言し、依存変数を明示的に宣言する必要はありません。 |
算出プロパティ | useMemo を使用して算出プロパティを作成します。最初のパラメータは算出プロパティの値を返す関数で、2番目のパラメータは依存関係の配列です。 | $ 式を使用して算出プロパティを作成し、依存変数が変更されると自動的に更新されます。 |
条件付きレンダリング | JavaScriptの三項演算子を使用して、条件付きレンダリングロジックを表現します。 | 従来のテンプレート言語({#if} {:else if} {:else} {/if} )に似た構文を採用しており、複雑なロジックの場合に明確です。 |
ループ | map を使用して配列を走査し、コンポーネントを返してループレンダリングを実現し、key を設定する必要があります。 | each を通じてループレンダリングを実行し、(variable.id) はレンダリングのkey を表します。 |
グローバルステート管理 | createContext を通じてContext を作成し、ルートコンポーネントでProvider で子コンポーネントをラップし、子コンポーネントはuseContext を使用してステートを取得します。 | writable を使用してグローバルストアを宣言します。コンポーネントでは、$+変数名 を使用してそれを読み取り、store.update() を使用してそれを更新します。構文はより簡潔です。 |
非同期レンダリング | React18は、非同期コードを実行するためのuse フックを導入しました。非同期コンポーネントはSuspense でラップされ、ローディングとエラーを処理するためにErrorBoundary と一緒に使用できます。 | 非同期レンダリングとエラーキャッチを処理するために、JavaScript({#await} {:then} {:catch} {/await} )に似たテンプレート構文を提供します。 |
0. レンダリングモード
ReactとSvelteはどちらもリアクティブUIフレームワークですが、そのレンダリングモードは全く異なります。 Reactは、Virtual DOMによって変更が必要なページの部分を計算します。これは、すべてのReactアプリケーションが組み込みのRuntimeを持っている必要があることを意味します。つまり、Virtual DOMを計算し、ページをレンダリングするためのコードが含まれています。これにより、コードサイズが増加します。たとえば、Next.jsで構築されたHello Worldアプリケーションには70kbのJavaScriptコードがあります。
Svelteは全く異なる戦略を採用しています。アプリケーションのビルド段階で、Svelteは開発者が記述したコードをコンパイルし、Runtimeの代わりにコンパイラを使用します。最終的に生成される製品には、Svelteライブラリコードは含まれていません。したがって、SvelteのHello Worldアプリケーションはわずか3kbです。
Svelteは非JSコードをJSコードにコンパイルしますが、Reactアプリケーションのコードは純粋なJSコードですが、驚くべきことに、SvelteはネイティブJavaScriptのサードパーティライブラリとうまく連携できます。ただし、Reactはより成熟したエコシステムを持っています。
1. state
まず、2つのフレームワークで最も単純なステート管理を実現する方法を比較します。
Reactでは、useState
を使用してリアクティブステートcount
とその対応するsetter関数setCount()
を生成する必要があります。setCount()
を呼び出してcount
の値を更新すると、UIが再レンダリングされます。
import { useState } from "react"; function Counter() { // useStateを使用してステートcountを0に初期化し、更新関数setCountを取得します const [count, setCount] = useState(0); return ( <div> {/* ボタンをクリックすると、setCountを呼び出してcountの値を増やし、現在のcount値を表示します */} <button onClick={() => setCount(count + 1)}>Count is {count}</button> </div> ); }
Svelteでは、変数がlet
キーワードで宣言されている限り、それはリアクティブです。リアクティブ変数count
はSvelteコンポーネントコードで宣言されています。Svelteコンポーネントコードは、script
、style
、およびtemplate
の3つの部分に分かれています。違いは、Svelteでは、HTMLをtemplate
タグでラップする必要がないことです。count
の値を変更するには、通常の変数のように操作するだけで、フレームワークは自動的にリアクティブUIの更新を実行します。
<script> // リアクティブ変数countを宣言し、0に初期化します let count = 0; </script> {#if true} <!-- ボタンをクリックすると、countの値を増やし、現在のcount値を表示します --> <button on:click={() => count++}> count is {count} </button> {/if}
2. props
次に、2つのフレームワークでプロパティを受信して渡す方法を見てみましょう。 Reactの関数型コンポーネントでは、プロパティは関数パラメータの形式で受信され、分割代入メソッドは通常、プロパティの特定の値を取得するために使用されます。
function ColoredBox({color}) { // 分割代入を使用してcolorプロパティの値を取得し、表示します return ( <p>You picked: {color}</p> ) }
Svelteでは、変数を宣言するときに、その前にexport
キーワードを追加すると、その変数が外部から渡されるプロパティであることを意味します。
<script> // colorを外部から渡されるプロパティとして宣言します export let color; </script> {#if color} You picked: {color} {/if}
変数渡しに関して、2つの構文は似ており、どちらもHTML属性の形式です。
<App color={color} />
Svelteは、プロパティ渡しをより簡潔にするための構文糖も提供しています。
<App {color} />
Reactのプロパティはコンポーネントにすることができますが、Svelteはこの方法をサポートしていないことに注意してください。
<App head={<Head />} />
3. children
Reactでは、props.children
を通じて子コンポーネントの情報を取得できます。
function ParentComponent(props) { // props.childrenを通じて子コンポーネントのコンテンツを取得し、表示します return ( <div> {props.children} </div> ); }
Svelteでは、この機能はスロットslot
を通じて実装する必要があります。
<!-- Widget.svelte --> <div> <slot> <!-- 子コンポーネントのコンテンツがない場合、このコンテンツがデフォルトで表示されます --> 子コンポーネントのコンテンツがない場合、このコンテンツがデフォルトで表示されます。 </slot> </div> <!-- App.svelte --> <Widget /> <!-- ⬆️このコンポーネントはデフォルトのコンテンツを表示します --> <Widget> <p>この子コンポーネントはデフォルトのコンテンツを上書きします</p> </Widget>
Svelteは名前付きスロットもサポートしています。
<!-- Widget.svelte --> <div> <slot name="header" /> <p>ヘッダーとフッターの間のコンテンツ</p> <slot name="footer" /> </div> <!-- App.svelte --> <Widget> <h1 slot="header">Hello</h1> <p slot="footer">Svelte Industries</p> </Widget>
4. ライフサイクル
Reactの関数型コンポーネントでは、ライフサイクルはuseEffect
を通じてシミュレートする必要があります。
useEffect(() => { // コンポーネントが初期化されるときに実行され、onMountと同等です console.log('Component initialized'); return () => { // コンポーネントがアンマウントされるときに実行され、onDestroyと同等です console.log('Component unmounted'); } }, [])
Svelteでは、対応するライフサイクル関数をscript
でインポートするだけです。
<script> import { onMount, onDestroy } from 'svelte'; onMount(() => { console.log('Component mounted'); }); onDestroy(() => { console.log('Component unmounted'); }); </script>
5. 副作用
Reactでは、副作用はuseEffect
を通じて宣言され、副作用が依存する変数はuseEffect
の2番目のパラメータを通じて手動で宣言されます。
function Counter() { const [count] = useState(0); useEffect(() => { // countが変更されたら、document.titleを更新します document.title = `count is ${count}`; }, [count]) }
Svelteでは、副作用は$
記号で始まるリアクティブ式を通じて宣言できます。
<script> let count = 0; // countが変更されたら、document.titleを自動的に更新します $: document.title = `count is ${count}`; </script>
$:
の後のステートメントは自動的にリアクティブ機能を持ちます。ステートメントで参照されている変数が変更されると、ステートメントは自動的に実行されます。これは、変数の変更の副作用と同等です。比較すると、Svelteは副作用ステートメントが依存する変数を明示的に宣言する必要がなく、Reactよりも使いやすいです。
6. 算出プロパティ
算出プロパティとは、Vueのcomputed
と同様に、値がstate
に依存する変数を指します。Reactでは、算出プロパティはuseMemo
を通じて作成できます。useMemo
の最初のパラメータは関数で、その戻り値は算出プロパティの値です。2番目のパラメータは依存関係の配列です。依存関係の配列内の変数が変更されると、算出プロパティの値が再計算されます。
function Counter() { const [count] = useState(0); // useMemoを使用して、countに依存する算出プロパティdoubleを作成します const double = useMemo(() => count * 2, [count]); }
Svelteでは、前のセクションで説明した$
式を使用して、算出プロパティを作成することもできます。
<script> let count = 0; // countに依存する算出プロパティdoubledを作成します。countが変更されると、doubledが再割り当てされます $: doubled = count * 2 </script>
7. 条件付きレンダリング
ReactはJSXを使用してUIを記述するため、JavaScriptの三項演算子を使用して、条件付きレンダリングのロジックを実装できます。
function Counter() { const [count] = useState(0); return <> {/* countの値に応じて条件付きレンダリング */} { count > 1000 ? <p>Big</p> : <p>Small</p> } </> }
Svelteは、従来のテンプレート言語に似た構文を使用して、条件付きレンダリングのロジックを表現します。
<script> let count = 0 </script> {#if count > 1000} <p>Big</p> {:else if count > 500} <p>Medium</p> {:else} <p>Small</p> {/if}
比較すると、Svelteの構文は少し面倒ですが、else if
ステートメントが存在するため、複雑な条件付きレンダリングロジックを表現する際には、Reactの三項演算子よりも明確です。
8. ループ
Reactでは、map
を使用して配列を走査し、一連のコンポーネントを返して、ループレンダリングを実現できます。
function Looper() { const items = [ { id: 1, name: "foo" }, { id: 2, name: "bar" }, { id: 3, name: "baz" } ]; return <> {/* mapを使用してitems配列を走査し、コンポーネントをレンダリングしてキーを設定します */} {items.map(item => <p key={item.id}>{item.name}</p>)} </> }
Svelteでは、each
を通じてループレンダリングを実行できます。(item.id)
は、レンダリングのkey
がitem.id
であることを示します。
<script> const items = [ { id: 1, name: "foo" }, { id: 2, name: "bar" }, { id: 3, name: "baz" } ]; </script> {#each items as item (item.id)} <p>{item.name}</p> {/each}
9. グローバルステート管理
Reactで、複数のコンポーネントで共有されるステートを作成する場合は、Context
を通じて実現できます。まず、createContext
を使用してCountContext
を作成し、次に、このContext
のProvider
を使用して、ルートコンポーネントApp
の子コンポーネントをラップします。このようにして、子コンポーネントCounter
では、useContext
を通じてCountContext
のコンテンツを取得できます。
// context.js import { createContext } from 'react'; // CountContextを作成し、0に初期化します export const CountContext = createContext(0); // Counter.jsx import { useContext } from 'react'; import { CountContext } from './context'; function Counter() { // useContextを使用してCountContextの値を取得します const count = useContext(CountContext); return <div>{count}</div>; } // App.jsx import { CountContext } from './context'; import { Counter } from './Counter'; function App() { return <> {/* CountContext.Providerを使用して子コンポーネントをラップし、ステートを渡します */} <CountContext.Provider value={42}> <Counter /> </CountContext.Provider> </>; }
Svelteでは、writable
を通じてグローバルストアを宣言できます。グローバルステートを使用する必要があるコンポーネントでストアをインポートし、$+変数名
の方法でストアを読み取り、store.update()
を呼び出してストアを更新します。
// store.js import { writable } from "svelte/store"; // グローバルストアcountを宣言し、0に初期化します export const count = writable(0); // App.svelte <script> import { count } from "./store"; </script> <button onClick={() => count.update(c => c + 1)}> {/* $countを使用してグローバルステートcountの値を読み取ります */} {$count} </button>
個人的には、Svelteのグローバルステート管理構文の方が簡潔だと思います。Provider
を記述する必要はなく、$
記号だけでグローバルステートを使用できます。
10. 非同期レンダリング
React18では、非同期レンダリングメカニズムが導入されました。新しいuse
フックを使用して非同期コードを実行でき、その効果はawait
ステートメントに似ています。use
を使用するコンポーネントは非同期コンポーネントです。コンポーネントをレンダリングする前に非同期コードが実行されるのを待つ必要があるためです。
function AsyncComponent() { const number = use(Promise.resolve(100)); return <p>{number}</p>; }
非同期コンポーネントを使用する場合、Suspense
コンポーネントでラップし、fallback
コンポーネントを渡すことができます。非同期コンポーネントがまだレンダリングされていない場合にfallback
コンポーネントが表示され、ローディング状態を追加するために使用されます。さらに、非同期レンダリングプロセス中にエラーが発生するのを防ぐために、ErrorBoundary
を使用してエラーをキャッチすることもでき、エラーが発生したときに対応するfallback
コンポーネントが表示され、ページがクラッシュして空白になるのを防ぎます。
function App() { return ( <ErrorBoundary fallback={<ErrorPage />}> <Suspense fallback={<LoadingSpinner/>}> <ComponentWithAsyncData /> </Suspense> </ErrorBoundary> ) }
Svelteでは、フレームワークはJavaScriptに似たテンプレート構文を提供して、非同期レンダリングとエラーキャッチのニーズを満たします。
<script> const promise = Promise.resolve(69); </script> {#await promise} <LoadingSpinner/> {:then number} <p>The number is {number}</p> {:catch error} <ErrorPage {error} /> {/await}
Summary
この記事では、ReactとSvelteのフレームワークを、レンダリングモード、ステート管理、プロパティ渡し、子コンポーネントの取り扱い、ライフサイクル、副作用、算出プロパティ、条件付きレンダリング、ループ、グローバルステート管理、非同期レンダリングなど、10個の側面から詳細に比較し、基本的な使用方法を網羅しました。この記事を読むことで、読者はSvelteについてより包括的な理解を得られたと思います。これらの2つのUIフレームワークはそれぞれ独自の利点があります。どちらがより高く評価されますか?コメントセクションであなたの意見を共有してください。
References:
- https://www.youtube.com/watch?v=MnpuK0MK4yo
- https://fireship.io/lessons/svelte-for-react-developers/
Leapcell: The Best of Serverless Web Hosting
最後に、nodejsサービスを展開するのに最適なプラットフォームをお勧めします:Leapcell
🚀 Build with Your Favorite Language
JavaScript、Python、Go、Rustで軽々と開発。
🌍 Deploy Unlimited Projects for Free
使用量のみを支払う - リクエストも課金もなし。
⚡ Pay-as-You-Go, No Hidden Costs
アイドル料金はなし、シームレスなスケーラビリティのみ。
🔹 Follow us on Twitter: @LeapcellHQ