Referensi cepat Solid.js. Signals, effects, memos, components, context, dan control flow. Perfect buat developer React yang mau coba reactivity tanpa virtual DOM.
Login atau daftar akun gratis untuk membaca cheat sheet ini.
# Vite template (recommended)
npm create vite@latest my-app -- --template solid-ts
# atau degit (lebih cepat)
npx degit solidjs/templates/ts my-app
cd my-app && npm
Verifikasi instalasi:
npm run devSignal adalah unit reactivity dasar di Solid. Mirip useState di React, tapi lebih granular.
import { createSignal } from 'solid-js';
function Counter() {
const [count, setCount] = createSignal(0);
return (
<button onClick={() =>
Perbedaan penting sama React: signal adalah function. Kamu harus panggil count() buat baca nilainya.
// Solid
const [count, setCount] = createSignal(0);
console.log(count()); // 0 (panggil sebagai function)
// React
const [count, setCount] = useState(
const [count, setCount] = createSignal(0);
// Set langsung
setCount(5);
// Dari nilai sebelumnya
setCount(prev => prev + 1);
// Callback dengan return false = batalkan update
const [user, setUser] = createSignal({ name: 'Galih', age: 25 });
// Update properti tertentu
setUser(prev => ({ ...prev, age: 26 }));
// Array
const [
// Default: signal ngga trigger kalau nilai barunya sama (Object.is)
const [count, setCount] = createSignal(0);
setCount(0); // Tidak trigger re-render
// Disable equality check
const [obj, setObj]
Memo caching nilai computed. Recompute cuma kalau dependency berubah.
import { createSignal, createMemo } from 'solid-js';
function PriceCalculator() {
const [price, setPrice] = createSignal(100);
const [quantity, setQuantity]
Memo sebagai read-only signal:
const first = createSignal(1);
const second = createSignal(2);
const sum = createMemo(() => first[0]() + second[0]());
// sum() = 3
Effect jalan setiap kali dependency berubah. Untuk side effects (DOM, API calls, logging).
import { createSignal, createEffect } from 'solid-js';
function Logger() {
const [count, setCount] = createSignal(0);
// Jalan saat count berubah
createEffect(() => {
console.
import { createEffect, onCleanup } from 'solid-js';
function Timer() {
const [seconds, setSeconds] = createSignal(0);
createEffect(() => {
const
Sama kayak createEffect tapi jalan saat render, bukan setelah. Tidak defer.
import { createRenderEffect } from 'solid-js';
createRenderEffect(() => {
document.title = `Page ${currentPage()}`;
});import { createEffect, on } from 'solid-js';
// Explicit dependencies
createEffect(on(count, () => {
console.log('Count changed to:', count());
}));
// Defer: jangan jalan saat pertama kali
createEffect(on
import { JSX } from 'solid-js';
interface GreetingProps {
name: string;
age?: number;
}
function Greeting(props: GreetingProps):
// WRONG: destructuring props break reactivity di Solid
function Bad({ name }: { name: string }) {
return <h1>{name}</h1>;
}
// RIGHT: akses langsung dari props
function
import { splitProps, mergeProps } from 'solid-js';
// splitProps: pisahkan props ke beberapa object
function Button(allProps) {
const [buttonProps, rest] = splitProps(allProps, ['type',
Conditional rendering. Lebih efisien daripada ternary.
import { Show } from 'solid-js';
function App() {
const [loggedIn, setLoggedIn] = createSignal(false);
return (
<Show
when
Looping array dengan key-based reconciliation.
import { For } from 'solid-js';
function TodoList() {
const [todos, setTodos] = createSignal([
{ id: 1, text: 'Belajar Solid' },
{ id: 2, text:
Looping array dengan index-based reconciliation. Berguna kalau data ngga punya stable key.
import { Index } from 'solid-js';
<Index each={items()}>
{(item, index) => (
<div>{index}: {item()}</div>
)}
</IndexMultiple conditional branches.
import { Switch, Match } from 'solid-js';
function StatusMessage(props) {
return (
<Switch fallback={<p>Unknown status</p>}>
<Match when
import { ErrorBoundary } from 'solid-js';
function App() {
return (
<ErrorBoundary
fallback={(err, reset) => (
<div>
<
import { Suspense } from 'solid-js';
import { lazy } from 'solid-js';
const LazyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<
import { createContext, useContext } from 'solid-js';
// Bikin context
const ThemeContext = createContext<{ theme: string; toggle: () => void }>();
Fetch async data dengan tracking state (loading, error, data).
import { createResource } from 'solid-js';
// Fetcher function
async function fetchUser(id: number) {
const res = await fetch(`/api/users/${id}`);
const [userId, setUserId] = createSignal(1);
const [user] = createResource(userId, fetchUser);
// userId berubah = refetch otomatis
<button onClick={() => setUserId(2const [data, { refetch, mutate }] = createResource(fetchData);
// Refetch
refetch();
// Mutate: update data tanpa fetch
mutate({ ...data(), status: 'updated' });const [users] = createResource(fetchUsers);
const [posts] = createResource(() => users()?.[0]?.id, fetchPosts);
// posts di-fetch setelah users selesaiStore adalah reactive proxy untuk nested objects/arrays.
import { createStore } from 'solid-js/store';
function App() {
const [state, setState] = createStore({
user: { name: 'Galih', settings: { dark: false } },
import { createStore, produce } from 'solid-js/store';
const [state, setState] = createStore({ items: [{ id: 1, qty: 1 }] });
// Mutate secara draft
setState(produce(s => {
Solid punya lifecycle yang minimal karena Signals + Effects udah cukup.
import { onMount, onCleanup } from 'solid-js';
function Component() {
// Setelah DOM pertama kali render
onMount(() => {
console.log('Mounted!');
const observer = new IntersectionObserver(callback);
function Form() {
const [value, setValue] = createSignal('');
const handleSubmit = (e: Event) => {
Solid delegasikan events ke document root secara default. Tapi bind:propertyName bisa dipake buat two-way binding.
// Controlled input
<input value={value()} onInput={e => setValue(e.currentTarget.value)} />
// bind: (Solid 1.8+)
<input bind:value={value} />import { createSignal } from 'solid-js';
function Canvas() {
let canvas: HTMLCanvasElement;
// canvas langsung tersedia setelah render
onMount(() => {
const ctx = canvas.getContext(
src/routes/
index.tsx -> /
about.tsx -> /about
users/
index.tsx -> /users
[id].tsx -> /users/:idimport { createRouteData } from 'solid-start';
export function routeData() {
return createRouteData(async () => {
const users = await fetch('https://api.example.com/users');
| Aspek | Solid.js | React |
|---|---|---|
| Reactivity | Fine-grained Signals | Virtual DOM diffing |
| Re-render | Hanya komponen yang berubah | Komponen + children |
| State | createSignal (function) | useState (value) |
| Memo | Explicit createMemo | useMemo (deklarasi) |
| Effect | createEffect (auto-track) | useEffect (deps array) |
| Props | Reactive (akses via props.x) | Plain object |
| Virtual DOM | Tidak ada | Ada |
| Bundle size | ~7KB | ~45KB |
| SSR | SolidStart | Next.js |