Lifting State Up — React

Bayangin form login dengan komponen di kiri dan di kanan. Pas user ngetik email belum valid, button harus disabled. Tapi gak tahu apa email valid — itu state…

Kadang dua komponen bersaudara (sibling, anak dari parent yang sama) harus menampilkan data yang sama. Kalau masing-masing menyimpan state sendiri, mereka gak akan pernah sepakat. Solusinya: pindahkan state itu ke parent terdekat yang membungkus keduanya, lalu turunkan ke anak-anaknya lewat props. Teknik ini namanya lifting state up, mengangkat state ke atas. Bayangin dua kasir di satu warung yang mencatat stok di buku masing-masing. Kasir A menjual roti terakhir, tapi buku kasir B masih bilang ada satu. Warung yang rapi menaruh satu buku stok di meja tengah, dan kedua kasir membaca dan menulis di buku yang sama.

🧪 Tebakan cepat: NamaInput dan Sapaan masing-masing punya useState('Tamu'). Kamu mengetik "Rina" di NamaInput. Sapaan menampilkan "Halo, Rina!" atau tetap "Halo, Tamu!"? Tebak dulu, jawabannya ada di bagian "Dua saudara yang gak sepakat".

Dua saudara yang gak sepakat

function NamaInput() {
  const [nama, setNama] = useState('Tamu')
  return <input value={nama} onChange={(e) => setNama(e.target.value)} />
}

function Sapaan() {
  const [nama] = useState('Tamu') // state milik Sapaan sendiri
  return <p>Halo, {nama}!</p>
}

function App() {
  return (
    <div>
      <NamaInput />
      <Sapaan />
    </div>
  )
}

Kamu mengetik "Rina". State nama milik NamaInput jadi 'Rina', tapi Sapaan punya state sendiri yang tetap 'Tamu'. Hasilnya "Halo, Tamu!". Itu jawaban tebakannya. Di React, data cuma mengalir satu arah, dari parent ke anak lewat props. Ini disebut one-way data flow. Saudara gak bisa membaca state saudaranya, jadi Sapaan gak pernah tahu ada ketikan baru.

Angkat state ke parent terdekat

function NamaInput({ nama, onNamaChange }) {
  return <input value={nama} onChange={(e) => onNamaChange(e.target.value)} />
}

function Sapaan({ nama }) {
  return <p>Halo, {nama}!</p>
}

function App() {
  const [nama, setNama] = useState('Tamu') // satu-satunya tempat nama disimpan

  return (
    <div>
      <NamaInput nama={nama} onNamaChange={setNama} />
      <Sapaan nama={nama} />
    </div>
  )
}
Langkah Yang terjadi
1 Kamu mengetik sampai kolomnya berisi "Rina", onChange di NamaInput jalan
2 NamaInput memanggil onNamaChange('Rina'), yaitu setNama milik App
3 State nama di App jadi 'Rina', dan App render ulang
4 App mengirim nama yang baru ke NamaInput dan Sapaan, keduanya render ulang
5 Sapaan menampilkan "Halo, Rina!"

Pola yang sama untuk angka

function Display({ value }) {
  return <span id="display">{value}</span>
}

function Controls({ onIncrement }) {
  return <button id="add" onClick={onIncrement}>+1</button>
}

function App() {
  const [count, setCount] = useState(0)

  return (
    <div>
      <Display value={count} />
      <Controls onIncrement={() => setCount((c) => c + 1)} />
    </div>
  )
}

Kapan dan bagaimana mengangkat

Angkat state saat dua komponen atau lebih butuh data yang sama. Kalau cuma satu komponen yang memakainya, biarkan state-nya lokal di komponen itu. Langkahnya:

  1. Cari komponen mana saja yang butuh data itu.
  2. Cari parent terdekat yang membungkus semuanya.
  3. Pindahkan useState ke parent itu.
  4. Turunkan nilainya lewat props (value, nama).
  5. Turunkan function untuk mengubahnya lewat props (onIncrement, onNamaChange).

⚠️ Jebakan yang sering ketemu

TL;DR: Saat dua komponen butuh data yang sama, angkat state-nya ke parent terdekat yang membungkus keduanya. Teknik ini namanya lifting state up. Parent menyimpan state dengan useState, menurunkan nilainya lewat props (value={count}, nama={nama}), dan menurunkan function untuk mengubahnya (onIncrement, onNamaChange). Anak memanggil function itu, misalnya onNamaChange(e.target.value), parent mengganti state, lalu semua anak render ulang dengan nilai yang sama. Data mengalir satu arah, dari atas ke bawah. State yang cuma dipakai satu komponen tetap lokal.

Yang akan kamu pelajari