BelajarKoding Logobelajarkoding

Platform belajar web development Indonesia. Artikel, cheat sheets, roadmap, dan code challenges untuk developer Indonesia.

Navigasi

  • Artikel
  • Cheat Sheets
  • Roadmap
  • Challenges
  • Pricing
  • Search

Produk Lain

  • JagoHermes
  • KelasClaude
  • KilatKoding
  • BelajarVibeCoding
  • JualanKoding

Support

  • Privacy Policy
  • Terms of Service
  • Email

© 2026 BelajarKoding. All rights reserved.

Galih PratamaBagian dari ekosistem Galih Pratama
belajarkoding LogobyGalih Pratama
RoadmapArtikelCheat SheetsChallengesUpgrade
belajarkoding LogobyGalih Pratama
RoadmapArtikelCheat SheetsChallengesUpgrade
belajarkoding LogobyGalih Pratama
RoadmapArtikelCheat SheetsChallengesUpgrade

Daftar Isi

InstalasiSetup ProjectSignals (State Management)createSignalUpdate FunctionsSignal dengan Object/ArraycreateSignal dengan EqualsDerived StatecreateMemoEffectscreateEffectEffect dengan CleanupcreateRenderEffecton (Dependency Control)ComponentsBasic ComponentProps destructuring warningsplitProps dan mergePropsControl FlowShowForIndexSwitch dan MatchErrorBoundarySuspenseContextcreateContext dan useContextResources (Async Data)createResourceResource dengan Source SignalMutable Resource (refetch manual)Multiple resourcesStores (Deep Reactive State)createStoreStore dengan produce (Immer-like)LifecycleEvent HandlingEvent DelegationRefsSolidStart (SSR Framework)File-based RoutingLoad Functions (Server-side data)Comparison: Solid vs ReactGlossary
Solid.jsJavaScriptFrontend

Solid.js Cheat Sheet

Referensi cepat Solid.js. Signals, effects, memos, components, context, dan control flow. Perfect buat developer React yang mau coba reactivity tanpa virtual DOM.

TypeScript10 min read1.832 kata
Silakan login atau daftar untuk membaca cheat sheet ini.

Baca Cheat Sheet Lengkap

Login atau daftar akun gratis untuk membaca cheat sheet ini.

LoginDaftar Gratis
Share:

#Instalasi

#Setup Project

bash
# 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 install
 
# SolidStart (full-stack, kayak Next.js untuk Solid)
npm create solid@latest

Verifikasi instalasi:

bash
npm run dev

#Signals (State Management)

#createSignal

Signal adalah unit reactivity dasar di Solid. Mirip useState di React, tapi lebih granular.

tsx
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.

tsx
// Solid
const [count, setCount] = createSignal(0);
console.log(count());  // 0 (panggil sebagai function)
 
// React
const [count, setCount] = useState(

#Update Functions

tsx
const [count, setCount] = createSignal(0);
 
// Set langsung
setCount(5);
 
// Dari nilai sebelumnya
setCount(prev => prev + 1);
 
// Callback dengan return false = batalkan update

#Signal dengan Object/Array

tsx
const [user, setUser] = createSignal({ name: 'Galih', age: 25 });
 
// Update properti tertentu
setUser(prev => ({ ...prev, age: 26 }));
 
// Array
const [

#createSignal dengan Equals

tsx
// 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] 





#Derived State

#createMemo

Memo caching nilai computed. Recompute cuma kalau dependency berubah.

tsx
import { createSignal, createMemo } from 'solid-js';
 
function PriceCalculator() {
  const [price, setPrice] = createSignal(100);
  const [quantity, setQuantity] 









Memo sebagai read-only signal:

tsx
const first = createSignal(1);
const second = createSignal(2);
const sum = createMemo(() => first[0]() + second[0]());
 
// sum() = 3

#Effects

#createEffect

Effect jalan setiap kali dependency berubah. Untuk side effects (DOM, API calls, logging).

tsx
import { createSignal, createEffect } from 'solid-js';
 
function Logger() {
  const [count, setCount] = createSignal(0);
 
  // Jalan saat count berubah
  createEffect(() => {
    console.



#Effect dengan Cleanup

tsx
import { createEffect, onCleanup } from 'solid-js';
 
function Timer() {
  const [seconds, setSeconds] = createSignal(0);
 
  createEffect(() => {
    const








#createRenderEffect

Sama kayak createEffect tapi jalan saat render, bukan setelah. Tidak defer.

tsx
import { createRenderEffect } from 'solid-js';
 
createRenderEffect(() => {
  document.title = `Page ${currentPage()}`;
});

#on (Dependency Control)

tsx
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

#Components

#Basic Component

tsx
import { JSX } from 'solid-js';
 
interface GreetingProps {
  name: string;
  age?: number;
}
 
function Greeting(props: GreetingProps):









#Props destructuring warning

tsx
// WRONG: destructuring props break reactivity di Solid
function Bad({ name }: { name: string }) {
  return <h1>{name}</h1>;
}
 
// RIGHT: akses langsung dari props
function















#splitProps dan mergeProps

tsx
import { splitProps, mergeProps } from 'solid-js';
 
// splitProps: pisahkan props ke beberapa object
function Button(allProps) {
  const [buttonProps, rest] = splitProps(allProps, ['type', 









#Control Flow

#Show

Conditional rendering. Lebih efisien daripada ternary.

tsx
import { Show } from 'solid-js';
 
function App() {
  const [loggedIn, setLoggedIn] = createSignal(false);
 
  return (
    <Show
      when










#For

Looping array dengan key-based reconciliation.

tsx
import { For } from 'solid-js';
 
function TodoList() {
  const [todos, setTodos] = createSignal([
    { id: 1, text: 'Belajar Solid' },
    { id: 2, text: 














#Index

Looping array dengan index-based reconciliation. Berguna kalau data ngga punya stable key.

tsx
import { Index } from 'solid-js';
 
<Index each={items()}>
  {(item, index) => (
    <div>{index}: {item()}</div>
  )}
</Index

#Switch dan Match

Multiple conditional branches.

tsx
import { Switch, Match } from 'solid-js';
 
function StatusMessage(props) {
  return (
    <Switch fallback={<p>Unknown status</p>}>
      <Match when










#ErrorBoundary

tsx
import { ErrorBoundary } from 'solid-js';
 
function App() {
  return (
    <ErrorBoundary
      fallback={(err, reset) => (
        <div>
          <







#Suspense

tsx
import { Suspense } from 'solid-js';
import { lazy } from 'solid-js';
 
const LazyComponent = lazy(() => import('./HeavyComponent'));
 
function App() {
  return (
    <



#Context

#createContext dan useContext

tsx
import { createContext, useContext } from 'solid-js';
 
// Bikin context
const ThemeContext = createContext<{ theme: string; toggle: () => void }>();























#Resources (Async Data)

#createResource

Fetch async data dengan tracking state (loading, error, data).

tsx
import { createResource } from 'solid-js';
 
// Fetcher function
async function fetchUser(id: number) {
  const res = await fetch(`/api/users/${id}`);














#Resource dengan Source Signal

tsx
const [userId, setUserId] = createSignal(1);
const [user] = createResource(userId, fetchUser);
 
// userId berubah = refetch otomatis
<button onClick={() => setUserId(2

#Mutable Resource (refetch manual)

tsx
const [data, { refetch, mutate }] = createResource(fetchData);
 
// Refetch
refetch();
 
// Mutate: update data tanpa fetch
mutate({ ...data(), status: 'updated' });

#Multiple resources

tsx
const [users] = createResource(fetchUsers);
const [posts] = createResource(() => users()?.[0]?.id, fetchPosts);
 
// posts di-fetch setelah users selesai

#Stores (Deep Reactive State)

#createStore

Store adalah reactive proxy untuk nested objects/arrays.

tsx
import { createStore } from 'solid-js/store';
 
function App() {
  const [state, setState] = createStore({
    user: { name: 'Galih', settings: { dark: false } },

















#Store dengan produce (Immer-like)

tsx
import { createStore, produce } from 'solid-js/store';
 
const [state, setState] = createStore({ items: [{ id: 1, qty: 1 }] });
 
// Mutate secara draft
setState(produce(s => {


#Lifecycle

Solid punya lifecycle yang minimal karena Signals + Effects udah cukup.

tsx
import { onMount, onCleanup } from 'solid-js';
 
function Component() {
  // Setelah DOM pertama kali render
  onMount(() => {
    console.log('Mounted!');
    const observer = new IntersectionObserver(callback);




#Event Handling

tsx
function Form() {
  const [value, setValue] = createSignal('');
 
  const handleSubmit = (e: Event) => {


















#Event Delegation

Solid delegasikan events ke document root secara default. Tapi bind:propertyName bisa dipake buat two-way binding.

tsx
// Controlled input
<input value={value()} onInput={e => setValue(e.currentTarget.value)} />
 
// bind: (Solid 1.8+)
<input bind:value={value} />

#Refs

tsx
import { createSignal } from 'solid-js';
 
function Canvas() {
  let canvas: HTMLCanvasElement;
 
  // canvas langsung tersedia setelah render
  onMount(() => {
    const ctx = canvas.getContext(




#SolidStart (SSR Framework)

#File-based Routing

plaintext
src/routes/
  index.tsx        -> /
  about.tsx        -> /about
  users/
    index.tsx      -> /users
    [id].tsx       -> /users/:id

#Load Functions (Server-side data)

tsx
import { createRouteData } from 'solid-start';
 
export function routeData() {
  return createRouteData(async () => {
    const users = await fetch('https://api.example.com/users');














#Comparison: Solid vs React

AspekSolid.jsReact
ReactivityFine-grained SignalsVirtual DOM diffing
Re-renderHanya komponen yang berubahKomponen + children
StatecreateSignal (function)useState (value)
MemoExplicit createMemouseMemo (deklarasi)
EffectcreateEffect (auto-track)useEffect (deps array)
PropsReactive (akses via props.x)Plain object
Virtual DOMTidak adaAda
Bundle size~7KB~45KB
SSRSolidStartNext.js

#Glossary

  • Signal: Reactive primitive yang nampung nilai. Membaca signal (panggil sebagai function) otomatis daftarkan dependency.
  • Memo: Derived state yang di-cache. Recompute cuma kalau signal dependency berubah.
  • Effect: Side effect yang otomatis re-run saat dependency berubah.
  • Store: Deep reactive proxy untuk nested state. Update granular tanpa manual spread.
  • Resource: Async data fetcher yang tracking loading/error state otomatis.
  • Suspense: Boundary yang nungguin async operation (resource, lazy component) selesai.
  • Fine-grained reactivity: Update hanya bagian DOM yang spesifik berubah, tanpa re-render komponen.
  • OBSERVER pattern: Setiap Signal tahu siapa saja yang lagi baca nilainya, jadi update bisa ditargetkan presisi.
setCount
(
count
()
+
1
)}>
Count: {count()}
</button>
);
}
0
);
console.log(count); // 0 (baca langsung)
setCount(prev => prev > 10 ? prev : prev + 1);
items
,
setItems
]
=
createSignal
([
1
,
2
,
3
]);
setItems(prev => [...prev, 4]);
setItems(prev => prev.filter(x => x !== 2));
=
createSignal
({ x:
1
}, { equals:
false
});
setObj({ x: 1 }); // Trigger re-render
// Custom equality
const [data, setData] = createSignal(jsonString, {
equals: (a, b) => JSON.stringify(a) === JSON.stringify(b)
});
=
createSignal
(
2
);
const total = createMemo(() => price() * quantity());
return (
<div>
<p>Total: {total()}</p>
<button onClick={() => setQuantity(q => q + 1)}>Add</button>
</div>
);
}
// Recompute otomatis kalau first atau second berubah
log
(
'Count berubah:'
,
count
());
});
return <button onClick={() => setCount(c => c + 1)}>+1</button>;
}
interval
=
setInterval
(()
=>
{
setSeconds(s => s + 1);
}, 1000);
// Cleanup saat component unmount atau effect re-run
onCleanup(() => clearInterval(interval));
});
return <p>Time: {seconds()}s</p>;
}
(count, ()
=>
{
console.log('Count changed:', count());
}, { defer: true }));
JSX
.
Element
{
return (
<div>
<h1>Hello, {props.name}!</h1>
{props.age && <p>Age: {props.age}</p>}
</div>
);
}
// Usage
<Greeting name="Galih" age={25} />
Good
(
props
:
{
name
:
string
}) {
return <h1>{props.name}</h1>;
}
// RIGHT: pakai splitProps atau mergeProps
import { splitProps } from 'solid-js';
function Card(props: { title: string; body: string; footer?: string }) {
const [local, others] = splitProps(props, ['title']);
return (
<div {...others}>
<h2>{local.title}</h2>
<p>{props.body}</p>
</div>
);
}
'disabled'
]);
const [style, others] = splitProps(rest, ['class', 'style']);
return <button type={buttonProps.type} disabled={buttonProps.disabled}>Click</button>;
}
// mergeProps: gabungkan props (yang belakang menimpa)
function Greeting(props) {
const merged = mergeProps({ greeting: 'Hello', name: 'World' }, props);
return <h1>{merged.greeting}, {merged.name}!</h1>;
}
=
{
loggedIn
()}
fallback={<button onClick={login}>Login</button>}
>
<button onClick={logout}>Logout</button>
</Show>
);
}
// Nested Show
<Show when={data()}>
{(d) => <div>{d().name}</div>}
</Show>
'Bikin project'
},
]);
return (
<ul>
<For each={todos()}>
{(todo) => <li>{todo.text}</li>}
</For>
</ul>
);
}
// Dengan index
<For each={items()}>
{(item, index) => <div>{index()}: {item.name}</div>}
</For>
>
=
{props.status
===
'loading'
}>
<p>Loading...</p>
</Match>
<Match when={props.status === 'success'}>
<p>Success!</p>
</Match>
<Match when={props.status === 'error'}>
<p>Error occurred</p>
</Match>
</Switch>
);
}
p
>Error: {err.message}</
p
>
<button onClick={reset}>Retry</button>
</div>
)}
>
<MyComponent />
</ErrorBoundary>
);
}
Suspense
fallback
=
{<
div
>Loading...</
div
>}>
<LazyComponent />
</Suspense>
);
}
// Provider
function App() {
const [theme, setTheme] = createSignal('light');
const toggle = () => setTheme(t => t === 'light' ? 'dark' : 'light');
return (
<ThemeContext.Provider value={{ theme: theme(), toggle }}>
<Header />
<Main />
</ThemeContext.Provider>
);
}
// Consumer
function Header() {
const ctx = useContext(ThemeContext);
return (
<header class={ctx?.theme}>
<button onClick={ctx?.toggle}>Toggle Theme</button>
</header>
);
}
return res.json();
}
function UserProfile(props: { id: number }) {
const [user] = createResource(() => props.id, fetchUser);
return (
<div>
<Show when={!user.loading} fallback={<p>Loading...</p>}>
<h1>{user().name}</h1>
<p>{user().email}</p>
</Show>
</div>
);
}
)}>Next User</
button
>
todos: [{ id: 1, done: false, text: 'Belajar' }]
});
// Update nested
setState('user', 'name', 'Galih Pratama');
setState('user', 'settings', 'dark', true);
// Array update
setState('todos', 0, 'done', true);
setState('todos', t => [...t, { id: 2, done: false, text: 'Coding' }]);
return (
<div>
<p>{state.user.name}</p>
<p>Dark mode: {state.user.settings.dark ? 'On' : 'Off'}</p>
</div>
);
}
s.items[
0
].qty
+=
1
;
s.items.push({ id: 2, qty: 3 });
}));
observer.observe(document.getElementById('target'));
onCleanup(() => observer.disconnect());
});
}
e.
preventDefault
();
console.log('Submit:', value());
};
const handleInput = (e: InputEvent) => {
setValue((e.target as HTMLInputElement).value);
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={value()}
onInput={handleInput}
/>
<button type="submit">Submit</button>
</form>
);
}
'2d'
);
ctx?.fillRect(0, 0, 100, 100);
});
return <canvas ref={canvas!} width={500} height={500} />;
}
return users.json();
});
}
export default function Users() {
const users = useRouteData<typeof routeData>();
return (
<ul>
<For each={users()}>
{user => <li>{user.name}</li>}
</For>
</ul>
);
}