Reactivity
Declare state
React
import { useState } from "react";
export default function Name() {
const [name] = useState("John");
return <h1>Hello {name}</h1>;
}
Svelte 4
<script>
let name = "John";
</script>
<h1>Hello {name}</h1>
Update state
React
import { useEffect, useState } from "react";
export default function Name() {
const [name, setName] = useState("John");
useEffect(() => {
setName("Jane");
}, []);
return <h1>Hello {name}</h1>;
}
Svelte 4
<script>
let name = "John";
name = "Jane";
</script>
<h1>Hello {name}</h1>
Computed state
React
import { useState } from "react";
export default function DoubleCount() {
const [count] = useState(10);
const doubleCount = count * 2;
return <div>{doubleCount}</div>;
}
Svelte 4
<script>
let count = 10;
$: doubleCount = count * 2;
</script>
<div>{doubleCount}</div>
Templating
Minimal template
React
export default function HelloWorld() {
return <h1>Hello world</h1>;
}
Svelte 4
<h1>Hello world</h1>
Styling
React
import "./style.css";
export default function CssStyle() {
return (
<>
<h1 className="title">I am red</h1>
<button style={{ fontSize: "10rem" }}>I am a button</button>
</>
);
}
Svelte 4
<h1 class="title">I am red</h1>
<button style="font-size: 10rem;">I am a button</button>
<style>
.title {
color: red;
}
</style>
Loop
React
export default function Colors() {
const colors = ["red", "green", "blue"];
return (
<ul>
{colors.map((color) => (
<li key={color}>{color}</li>
))}
</ul>
);
}
Svelte 4
<script>
const colors = ["red", "green", "blue"];
</script>
<ul>
{#each colors as color (color)}
<li>{color}</li>
{/each}
</ul>
Event click
React
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
function incrementCount() {
setCount((count) => count + 1);
}
return (
<>
<p>Counter: {count}</p>
<button onClick={incrementCount}>+1</button>
</>
);
}
Svelte 4
<script>
let count = 0;
function incrementCount() {
count++;
}
</script>
<p>Counter: {count}</p>
<button on:click={incrementCount}>+1</button>
Dom ref
React
import { useEffect, useRef } from "react";
export default function InputFocused() {
const inputElement = useRef(null);
useEffect(() => inputElement.current.focus(), []);
return <input type="text" ref={inputElement} />;
}
Svelte 4
<script>
import { onMount } from "svelte";
let inputElement;
onMount(() => {
inputElement.focus();
});
</script>
<input bind:this={inputElement} />
Conditional
React
import { useState } from "react";
const TRAFFIC_LIGHTS = ["red", "orange", "green"];
export default function TrafficLight() {
const [lightIndex, setLightIndex] = useState(0);
const light = TRAFFIC_LIGHTS[lightIndex];
function nextLight() {
setLightIndex((lightIndex + 1) % TRAFFIC_LIGHTS.length);
}
return (
<>
<button onClick={nextLight}>Next light</button>
<p>Light is: {light}</p>
<p>
You must
{light === "red" && <span>STOP</span>}
{light === "orange" && <span>SLOW DOWN</span>}
{light === "green" && <span>GO</span>}
</p>
</>
);
}
Svelte 4
<script>
const TRAFFIC_LIGHTS = ["red", "orange", "green"];
let lightIndex = 0;
$: light = TRAFFIC_LIGHTS[lightIndex];
function nextLight() {
lightIndex = (lightIndex + 1) % TRAFFIC_LIGHTS.length;
}
</script>
<button on:click={nextLight}>Next light</button>
<p>Light is: {light}</p>
<p>
You must
{#if light === "red"}
<span>STOP</span>
{:else if light === "orange"}
<span>SLOW DOWN</span>
{:else if light === "green"}
<span>GO</span>
{/if}
</p>
Lifecycle
On mount
React
import { useState, useEffect } from "react";
export default function PageTitle() {
const [pageTitle, setPageTitle] = useState("");
useEffect(() => {
setPageTitle(document.title);
}, []);
return <p>Page title: {pageTitle}</p>;
}
Svelte 4
<script>
import { onMount } from "svelte";
let pageTitle = "";
onMount(() => {
pageTitle = document.title;
});
</script>
<p>Page title: {pageTitle}</p>
On unmount
React
import { useState, useEffect } from "react";
export default function Time() {
const [time, setTime] = useState(new Date().toLocaleTimeString());
useEffect(() => {
const timer = setInterval(() => {
setTime(new Date().toLocaleTimeString());
}, 1000);
return () => clearInterval(timer);
}, []);
return <p>Current time: {time}</p>;
}
Svelte 4
<script>
import { onDestroy } from "svelte";
let time = new Date().toLocaleTimeString();
const timer = setInterval(() => {
time = new Date().toLocaleTimeString();
}, 1000);
onDestroy(() => clearInterval(timer));
</script>
<p>Current time: {time}</p>
Component composition
Props
React
import UserProfile from "./UserProfile.jsx";
export default function App() {
return (
<UserProfile
name="John"
age={20}
favouriteColors={["green", "blue", "red"]}
isAvailable
/>
);
}
Svelte 4
<script>
import UserProfile from "./UserProfile.svelte";
</script>
<UserProfile
name="John"
age={20}
favouriteColors={["green", "blue", "red"]}
isAvailable
/>
Emit to parent
React
import { useState } from "react";
import AnswerButton from "./AnswerButton.jsx";
export default function App() {
const [isHappy, setIsHappy] = useState(true);
function onAnswerNo() {
setIsHappy(false);
}
function onAnswerYes() {
setIsHappy(true);
}
return (
<>
<p>Are you happy?</p>
<AnswerButton onYes={onAnswerYes} onNo={onAnswerNo} />
<p style={{ fontSize: 50 }}>{isHappy ? "😀" : "😥"}</p>
</>
);
}
Svelte 4
<script>
import AnswerButton from "./AnswerButton.svelte";
let isHappy = true;
function onAnswerNo() {
isHappy = false;
}
function onAnswerYes() {
isHappy = true;
}
</script>
<p>Are you happy?</p>
<AnswerButton on:yes={onAnswerYes} on:no={onAnswerNo} />
<p style="font-size: 50px;">{isHappy ? "😀" : "😥"}</p>
Slot
React
import FunnyButton from "./FunnyButton.jsx";
export default function App() {
return <FunnyButton>Click me!</FunnyButton>;
}
Svelte 4
<script>
import FunnyButton from "./FunnyButton.svelte";
</script>
<FunnyButton>Click me!</FunnyButton>
Slot fallback
React
import FunnyButton from "./FunnyButton.jsx";
export default function App() {
return (
<>
<FunnyButton />
<FunnyButton>I got content!</FunnyButton>
</>
);
}
Svelte 4
<script>
import FunnyButton from "./FunnyButton.svelte";
</script>
<FunnyButton />
<FunnyButton>I got content!</FunnyButton>
Context
React
import { useState } from "react";
import UserProfile from "./UserProfile";
import { UserContext } from "./UserContext";
export default function App() {
// In a real app, you would fetch the user data from an API
const [user, setUser] = useState({
id: 1,
username: "unicorn42",
email: "unicorn42@example.com",
});
function updateUsername(newUsername) {
setUser((userData) => ({ ...userData, username: newUsername }));
}
return (
<>
<h1>Welcome back, {user.username}</h1>
<UserContext.Provider value={{ ...user, updateUsername }}>
<UserProfile />
</UserContext.Provider>
</>
);
}
Svelte 4
<script>
import { setContext } from "svelte";
import UserProfile from "./UserProfile.svelte";
import createUserStore from "./createUserStore.js";
// In a real app, you would fetch the user data from an API
const userStore = createUserStore({
id: 1,
username: "unicorn42",
email: "unicorn42@example.com",
});
setContext("user", userStore);
</script>
<h1>Welcome back, {$userStore.username}</h1>
<UserProfile />
Form input
Input text
React
import { useState } from "react";
export default function InputHello() {
const [text, setText] = useState("Hello world");
function handleChange(event) {
setText(event.target.value);
}
return (
<>
<p>{text}</p>
<input value={text} onChange={handleChange} />
</>
);
}
Svelte 4
<script>
let text = "Hello World";
</script>
<p>{text}</p>
<input bind:value={text} />
Checkbox
React
import { useState } from "react";
export default function IsAvailable() {
const [isAvailable, setIsAvailable] = useState(false);
function handleChange() {
setIsAvailable(!isAvailable);
}
return (
<>
<input
id="is-available"
type="checkbox"
checked={isAvailable}
onChange={handleChange}
/>
<label htmlFor="is-available">Is available</label>
</>
);
}
Svelte 4
<script>
let isAvailable = false;
</script>
<input id="is-available" type="checkbox" bind:checked={isAvailable} />
<label for="is-available">Is available</label>
Radio
React
import { useState } from "react";
export default function PickPill() {
const [picked, setPicked] = useState("red");
function handleChange(event) {
setPicked(event.target.value);
}
return (
<>
<div>Picked: {picked}</div>
<input
id="blue-pill"
checked={picked === "blue"}
type="radio"
value="blue"
onChange={handleChange}
/>
<label htmlFor="blue-pill">Blue pill</label>
<input
id="red-pill"
checked={picked === "red"}
type="radio"
value="red"
onChange={handleChange}
/>
<label htmlFor="red-pill">Red pill</label>
</>
);
}
Svelte 4
<script>
let picked = "red";
</script>
<div>Picked: {picked}</div>
<input id="blue-pill" bind:group={picked} type="radio" value="blue" />
<label for="blue-pill">Blue pill</label>
<input id="red-pill" bind:group={picked} type="radio" value="red" />
<label for="red-pill">Red pill</label>
Select
React
import { useState } from "react";
const colors = [
{ id: 1, text: "red" },
{ id: 2, text: "blue" },
{ id: 3, text: "green" },
{ id: 4, text: "gray", isDisabled: true },
];
export default function ColorSelect() {
const [selectedColorId, setSelectedColorId] = useState(2);
function handleChange(event) {
setSelectedColorId(event.target.value);
}
return (
<select value={selectedColorId} onChange={handleChange}>
{colors.map((color) => (
<option key={color.id} value={color.id} disabled={color.isDisabled}>
{color.text}
</option>
))}
</select>
);
}
Svelte 4
<script>
let selectedColorId = 2;
const colors = [
{ id: 1, text: "red" },
{ id: 2, text: "blue" },
{ id: 3, text: "green" },
{ id: 4, text: "gray", isDisabled: true },
];
</script>
<select bind:value={selectedColorId}>
{#each colors as color}
<option value={color.id} disabled={color.isDisabled}>
{color.text}
</option>
{/each}
</select>
Webapp features
Render app
React
<!doctype html>
<html>
<body>
<div id="app"></div>
<script type="module" src="./main.jsx"></script>
</body>
</html>
Svelte 4
<!doctype html>
<html>
<body>
<div id="app"></div>
<script type="module" src="./app.js"></script>
</body>
</html>
Fetch data
React
import useFetchUsers from "./useFetchUsers";
export default function App() {
const { isLoading, error, data: users } = useFetchUsers();
return (
<>
{isLoading ? (
<p>Fetching users...</p>
) : error ? (
<p>An error occurred while fetching users</p>
) : (
users && (
<ul>
{users.map((user) => (
<li key={user.login.uuid}>
<img src={user.picture.thumbnail} alt="user" />
<p>
{user.name.first} {user.name.last}
</p>
</li>
))}
</ul>
)
)}
</>
);
}
Svelte 4
<script>
import useFetchUsers from "./useFetchUsers";
const { isLoading, error, data: users } = useFetchUsers();
</script>
{#if $isLoading}
<p>Fetching users...</p>
{:else if $error}
<p>An error occurred while fetching users</p>
{:else if $users}
<ul>
{#each $users as user}
<li>
<img src={user.picture.thumbnail} alt="user" />
<p>
{user.name.first}
{user.name.last}
</p>
</li>
{/each}
</ul>
{/if}