statevaluenotifierringanMenengah4 mnt baca

ValueNotifier & ValueListenableBuilder

State ringan tanpa setState: cocok untuk nilai tunggal.

Kenapa ValueNotifier Ada?

Bayangkan kamu punya halaman berisi ratusan widget, dan hanya satu angka kecil (misalnya jumlah item di keranjang) yang sering berubah. Kalau pakai setState, Flutter memanggil ulang seluruh method build milik widget itu. Itu berat dan boros, apalagi kalau halamanmu kompleks.

ValueNotifier lahir untuk kasus ini: state untuk satu nilai tunggal yang bisa berubah, dengan cara memberi tahu listener setiap nilai diganti. Tidak perlu StatefulWidget untuk logikanya, cukup satu objek kecil.

Contoh Sederhana: Counter

dart
final _counter = ValueNotifier<int>(0);

// mengubah nilai (cukup assign ke .value):
_counter.value++;

// menampilkan nilai:
ValueListenableBuilder<int>(
  valueListenable: _counter,
  builder: (context, nilai, child) {
    return Text('Angka: $nilai');
  },
)

Setiap _counter.value diganti, ValueNotifier memanggil notifyListeners(), dan ValueListenableBuilder me-rebuild hanya bagian builder-nya, bukan seluruh halaman.

Trik Performa: Parameter child

Widget di dalam builder yang tidak bergantung pada nilai sebaiknya dipindah ke parameter child, agar tidak ikut rebuild:

dart
ValueListenableBuilder<int>(
  valueListenable: _counter,
  child: const Icon(Icons.shopping_cart), // statis, tidak ikut rebuild
  builder: (context, nilai, child) {
    return Row(children: [
      child!,            // ikon dipakai ulang
      Text('$nilai'),    // hanya teks ini yang rebuild
    ]);
  },
)

Contoh Nyata: Toggle Favorit

dart
final _suka = ValueNotifier<bool>(false);

ValueListenableBuilder<bool>(
  valueListenable: _suka,
  builder: (context, suka, _) {
    return IconButton(
      icon: Icon(
        suka ? Icons.favorite : Icons.favorite_border,
        color: suka ? Colors.red : Colors.grey,
      ),
      onPressed: () => _suka.value = !suka,
    );
  },
)

Catatan teknis: ValueNotifier bisa dipakai juga di luar widget (misalnya di service sederhana) selama widget mendengarkannya lewat ValueListenableBuilder atau addListener. Tapi untuk state yang dipakai banyak layar, pertimbangkan Provider atau Riverpod agar struktur datanya jelas.

Edge Case: Nilai Sama Tidak Memicu Rebuild

ValueNotifier hanya memanggil notifyListeners() jika nilai baru tidak sama dengan nilai lama (perbandingan pakai ==). Jadi _counter.value = 5 dua kali berturut-turut hanya me-rebuild sekali.

Hati-hati dengan objek mutable:

dart
final _daftar = ValueNotifier<List<String>>(['a']);
_daftar.value.add('b');        // TIDAK rebuild! Objeknya sama, isinya berubah.
_daftar.value = [..._daftar.value, 'b']; // OK: assign objek baru

Kalau memang ingin memaksa rebuild setelah mutasi langsung, panggil _daftar.notifyListeners() secara manual.

Kapan JANGAN Pakai ValueNotifier

  • State kompleks dengan banyak field yang saling terkait (form, keranjang belanja penuh). Pakai model state yang lebih terstruktur agar logika tidak tercecer.
  • State lintas layar yang dalam (theme, sesi login). ValueNotifier tidak punya mekanisme scoping; pakai InheritedWidget, Provider, atau Riverpod.
  • State yang butuh async (loading dari API). ValueNotifier tidak menangani future/stream; pakai FutureBuilder/StreamBuilder.

Jangan Lupa Dispose

ValueNotifier yang kamu buat manual menahan listener di memori. Selalu dispose di StatefulWidget yang memilikinya:

dart
@override
void dispose() {
  _counter.dispose();
  super.dispose();
}

Lupa dispose adalah memory leak kecil yang menumpuk: setiap buka-tutup halaman menambah listener yang tidak pernah dibersihkan.

Tantangan

Toggle tanpa setState

Buat toggle favorit (ikon hati merah/abu) memakai ValueNotifier<bool>, tanpa StatefulWidget untuk logikanya.