SOLIDJS FRONTEND JAVASCRIPT WEB-DEVELOPMENT STATE-MANAGEMENT REACTIVITY SIGNALS WEB-PERFORMANCE UI-UX MODERN-WEB FRAMEWORK PERFORMANCE-OPTIMIZATION DX SOFTWARE-ARCHITECTURE

SolidJS: Membangun UI Reaktif Super Cepat dengan Pendekatan Signals

⏱️ 11 menit baca
👨‍💻

SolidJS: Membangun UI Reaktif Super Cepat dengan Pendekatan Signals

1. Pendahuluan

Di dunia web development yang terus berkembang, performa dan efisiensi adalah kunci. Kita sudah mengenal berbagai framework seperti React, Vue, dan Svelte, masing-masing dengan filosofi dan pendekatan reaktivitasnya sendiri. Namun, pernahkah Anda membayangkan sebuah framework yang bisa memberikan performa secepat Vanilla JavaScript, tetapi dengan pengalaman pengembangan yang menyenangkan seperti React, dan ukuran bundle yang minimal? Perkenalkan SolidJS.

SolidJS adalah framework JavaScript deklaratif untuk membangun user interface, yang dikenal karena performanya yang luar biasa. Rahasianya? SolidJS tidak menggunakan Virtual DOM. Alih-alih, ia mengadopsi pendekatan reaktivitas berbasis Signals, yang memungkinkan update DOM yang sangat granular dan efisien. Jika Anda seorang developer yang sudah terbiasa dengan React atau Vue, SolidJS mungkin terasa familiar secara sintaksis (karena menggunakan JSX), tetapi fundamental kerjanya sangat berbeda.

Artikel ini akan membawa Anda menyelami SolidJS, memahami konsep inti Signals, mengapa ia bisa begitu cepat, dan bagaimana Anda bisa mulai membangun aplikasi web yang super responsif dengannya. Mari kita bongkar revolusi reaktivitas ini! 🚀

2. Memahami Fondasi Reaktivitas SolidJS: Signals

Inti dari SolidJS adalah konsep Signals. Signals adalah nilai reaktif yang dapat berubah seiring waktu, dan ketika mereka berubah, SolidJS tahu persis bagian mana dari UI yang perlu di-update. Ini seperti sel di spreadsheet Excel: ketika satu sel berubah, semua sel lain yang bergantung padanya akan otomatis dihitung ulang.

Ada tiga primitive utama dalam sistem reaktivitas SolidJS:

2.1. createSignal: Jantung Reaktivitas

createSignal adalah cara Anda mendeklarasikan state reaktif. Ia mengembalikan array dengan dua elemen: fungsi getter untuk membaca nilai, dan fungsi setter untuk mengubah nilai.

import { createSignal } from 'solid-js';

// Membuat signal dengan nilai awal 0
const [count, setCount] = createSignal(0);

console.log(count()); // Mengakses nilai: 0

setCount(5); // Mengubah nilai
console.log(count()); // Mengakses nilai: 5

// Anda juga bisa menggunakan callback untuk update berdasarkan nilai sebelumnya
setCount(prevCount => prevCount + 1);
console.log(count()); // Mengakses nilai: 6

📌 Penting: Anda harus selalu memanggil count() sebagai fungsi untuk mendapatkan nilai saat ini, bukan count secara langsung. Ini karena count adalah fungsi yang memungkinkan SolidJS melacak dependensi.

2.2. createEffect: Bereaksi terhadap Perubahan

createEffect memungkinkan Anda menjalankan side effects (misalnya, memperbarui DOM, melakukan logging, atau memanggil API) setiap kali ada signal yang dibaca di dalamnya berubah.

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

const [name, setName] = createSignal("Alice");
const [age, setAge] = createSignal(30);

createEffect(() => {
  // Effect ini akan berjalan setiap kali name() atau age() berubah
  console.log(`Halo, nama saya ${name()} dan saya berusia ${age()} tahun.`);
});

// Awalnya akan log: "Halo, nama saya Alice dan saya berusia 30 tahun."

setName("Bob"); // Ini akan memicu effect lagi
// Output: "Halo, nama saya Bob dan saya berusia 30 tahun."

setAge(31); // Ini juga akan memicu effect
// Output: "Halo, nama saya Bob dan saya berusia 31 tahun."

💡 Tips Praktis: createEffect sangat berguna untuk interaksi dengan API browser (seperti DOM), logging, atau sinkronisasi dengan sistem eksternal.

2.3. createMemo: Derived State yang Di-cache

createMemo digunakan untuk membuat nilai komputasi yang bergantung pada satu atau lebih signals. Mirip dengan useMemo di React, tetapi di SolidJS, createMemo adalah primitive reaktif yang fundamental. Ia hanya akan dihitung ulang ketika dependensinya berubah, dan hasilnya di-cache.

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

const [firstName, setFirstName] = createSignal("John");
const [lastName, setLastName] = createSignal("Doe");

const fullName = createMemo(() => {
  console.log("Menghitung ulang full name...");
  return `${firstName()} ${lastName()}`;
});

console.log(fullName()); // Output: "Menghitung ulang full name..." "John Doe"

setFirstName("Jane"); // firstName berubah, fullName akan dihitung ulang
console.log(fullName()); // Output: "Menghitung ulang full name..." "Jane Doe"

// Jika kita panggil lagi tanpa perubahan dependensi, tidak akan dihitung ulang
console.log(fullName()); // Output: "Jane Doe" (tanpa log "Menghitung ulang...")

createMemo sangat efisien untuk menghitung nilai yang kompleks dan memastikan performa tetap terjaga.

3. Perbedaan Krusial: Tanpa Virtual DOM

Ini adalah salah satu perbedaan paling fundamental dan alasan utama SolidJS sangat cepat. Sementara framework seperti React dan Vue menggunakan Virtual DOM (representasi ringan dari DOM asli) untuk membandingkan perubahan dan kemudian memperbarui DOM yang sebenarnya, SolidJS mengambil pendekatan yang lebih langsung.

Bagaimana SolidJS Bekerja Tanpa Virtual DOM?

Ketika Anda menulis komponen SolidJS dengan JSX, JSX tersebut dikompilasi menjadi serangkaian instruksi Vanilla JavaScript yang secara langsung membuat dan memperbarui elemen DOM. SolidJS tidak perlu melakukan “diffing” atau perbandingan pohon Virtual DOM.

// Contoh JSX SolidJS (setelah kompilasi, ini akan menjadi Vanilla JS yang langsung manipulasi DOM)
function Counter() {
  const [count, setCount] = createSignal(0);
  return (
    <div>
      <p>Count: {count()}</p> {/* count() akan melacak dependensi di sini */}
      <button onClick={() => setCount(count() + 1)}>Increment</button>
    </div>
  );
}

⚠️ Implikasi Penting: Karena SolidJS langsung memperbarui DOM secara granular, tidak ada konsep “re-render” komponen seperti di React. Komponen di SolidJS hanya berjalan satu kali saat pertama kali di-mount. Reaktivitas terjadi di dalam template, di mana ekspresi count() akan otomatis diperbarui.

Ini berarti:

4. Mengelola UI dengan SolidJS: Komponen dan JSX

Meskipun SolidJS tidak memiliki Virtual DOM, sintaksis untuk mendefinisikan komponen dan menggunakan JSX akan terasa sangat familiar bagi developer React.

4.1. Struktur Komponen Dasar

Komponen di SolidJS adalah fungsi yang mengembalikan elemen JSX.

// src/App.jsx
import { render } from 'solid-js/web';
import { createSignal } from 'solid-js';

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

  return (
    <div>
      <h1>SolidJS Counter</h1>
      <p>Current count: {count()}</p>
      <button onClick={() => setCount(count() + 1)}>Tambah</button>
      <button onClick={() => setCount(count() - 1)}>Kurang</button>
    </div>
  );
}

render(() => <Counter />, document.getElementById('app'));

4.2. Props dan Reaktivitas

Props di SolidJS juga bekerja mirip dengan React, tetapi ada perbedaan penting dalam bagaimana reaktivitas ditangani. Props di SolidJS adalah objek getter yang reaktif.

// src/components/Greeting.jsx
import { createEffect } from 'solid-js';

function Greeting(props) {
  // props.name adalah getter, jadi panggil props.name()
  createEffect(() => {
    console.log(`Greeting component received new name: ${props.name}`);
  });

  return (
    <h2>Halo, {props.name}!</h2>
  );
}

export default Greeting;
// src/App.jsx
import { render } from 'solid-js/web';
import { createSignal } from 'solid-js';
import Greeting from './components/Greeting';

function App() {
  const [userName, setUserName] = createSignal("Dunia");

  return (
    <div>
      <Greeting name={userName()} /> {/* Mengirimkan nilai signal sebagai prop */}
      <button onClick={() => setUserName("SolidJS User")}>Ubah Nama</button>
    </div>
  );
}

render(() => <App />, document.getElementById('app'));

Ketika userName berubah, SolidJS akan memperbarui prop name di komponen Greeting, dan karena props.name adalah getter reaktif, ekspresi props.name di JSX dan createEffect akan otomatis diperbarui.

5. State Management Lanjutan dan Context API

Untuk state yang perlu dibagi antar komponen yang tidak memiliki hubungan parent-child langsung, SolidJS menyediakan Context API, mirip dengan React.

// src/contexts/AuthContext.jsx
import { createContext, createSignal, useContext } from 'solid-js';

const AuthContext = createContext();

export function AuthProvider(props) {
  const [user, setUser] = createSignal(null); // null jika belum login
  const [isAuthenticated, setIsAuthenticated] = createSignal(false);

  const login = (username, password) => {
    // Simulasi login
    if (username === 'dev' && password === 'solidjs') {
      setUser({ username: 'dev' });
      setIsAuthenticated(true);
      return true;
    }
    return false;
  };

  const logout = () => {
    setUser(null);
    setIsAuthenticated(false);
  };

  const store = {
    user,
    isAuthenticated,
    login,
    logout,
  };

  return (
    <AuthContext.Provider value={store}>
      {props.children}
    </AuthContext.Provider>
  );
}

export function useAuth() { return useContext(AuthContext); }
// src/App.jsx
import { render } from 'solid-js/web';
import { AuthProvider, useAuth } from './contexts/AuthContext';
import { createSignal, Show } from 'solid-js';

function LoginForm() {
  const { login } = useAuth();
  const [username, setUsername] = createSignal('');
  const [password, setPassword] = createSignal('');
  const [error, setError] = createSignal('');

  const handleSubmit = (e) => {
    e.preventDefault();
    if (login(username(), password())) {
      setError('');
    } else {
      setError('Username atau password salah.');
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" placeholder="Username" onInput={(e) => setUsername(e.target.value)} />
      <input type="password" placeholder="Password" onInput={(e) => setPassword(e.target.value)} />
      <button type="submit">Login</button>
      <Show when={error()}>
        <p style={{ color: 'red' }}>{error()}</p>
      </Show>
    </form>
  );
}

function UserProfile() {
  const { user, logout } = useAuth();
  return (
    <div>
      <p>Selamat datang, {user()?.username}!</p>
      <button onClick={logout}>Logout</button>
    </div>
  );
}

function AppContent() {
  const { isAuthenticated } = useAuth();
  return (
    <div>
      <h1>Aplikasi SolidJS</h1>
      <Show when={isAuthenticated()} fallback={<LoginForm />}>
        <UserProfile />
      </Show>
    </div>
  );
}

render(() => (
  <AuthProvider>
    <AppContent />
  </AuthProvider>
), document.getElementById('app'));

🎯 Tujuan Utama: Context API memungkinkan Anda menyediakan data dan fungsi ke seluruh pohon komponen tanpa perlu prop drilling, menjaga kode tetap bersih dan terorganisir.

6. Tips dan Best Practices SolidJS

Untuk memaksimalkan pengalaman Anda dengan SolidJS, berikut beberapa tips dan best practices:

Kesimpulan

SolidJS menawarkan pendekatan yang menyegarkan untuk membangun antarmuka pengguna di web. Dengan mengadopsi model reaktivitas berbasis Signals dan menyingkirkan Virtual DOM, SolidJS berhasil mencapai performa yang luar biasa dan efisiensi yang tinggi. Bagi developer yang mencari alternatif framework dengan fokus pada kecepatan, ukuran bundle kecil, dan pengalaman pengembangan yang modern, SolidJS adalah pilihan yang sangat menarik.

Meskipun konsep Signals mungkin memerlukan sedikit penyesuaian awal, terutama jika Anda terbiasa dengan model “re-render” React, investasi waktu untuk memahaminya akan terbayar lunas dengan aplikasi yang super cepat dan responsif. Selamat mencoba SolidJS dan rasakan sendiri perbedaannya!

🔗 Baca Juga