mutableStateOf: membuat status yang dapat diamati dan reaktivitas Compose

Penulis: IT Sectr Diterbitkan: 2026-06-28 Waktu membaca: 7 mnt

mutableStateOf adalah fungsi di Jetpack Compose yang membuat wadah status yang dapat diamati dan dapat diubah. Ketika nilai di dalam wadah ini berubah, Compose secara otomatis memulai rekomposisi semua komponen yang membaca status ini. Tanpa mutableStateOf, UI tidak akan dapat memperbarui secara reaktif saat data berubah. Menurut Google Android Developers, 2026, mutableStateOf adalah blok bangunan utama untuk status lokal di Compose.

Poin Utama

  • mutableStateOf membuat wadah MutableState yang dilacak oleh Compose Runtime
  • Rekomposisi dimulai secara otomatis saat value dari objek State ini berubah
  • Delegasi melalui var memungkinkan penggunaan mutableStateOf tanpa mengakses .value
  • Kunci di remember(mutableStateOf) tidak diperlukan — State memberi tahu Compose sendiri tentang perubahan
  • Sistem Snapshot menjamin konsistensi pembacaan di lingkungan multi-thread

Apa itu mutableStateOf di Jetpack Compose

mutableStateOf adalah fungsi dari paket compose.runtime yang membuat objek MutableState<T> yang menyimpan nilai dan dapat memberi tahu Compose Runtime tentang perubahan. Tanda tangan: fun <T> mutableStateOf(value: T, policy: SnapshotMutationPolicy<T> = structuralEquality()): MutableState<T>. Parameter policy menentukan kapan perubahan dianggap signifikan — saat kesetaraan struktural, kesetaraan referensial, atau tidak pernah.

MutableState adalah antarmuka dengan satu properti value: getter untuk membaca dan setter untuk menulis. Saat setter dipanggil, Compose Runtime mencatat perubahan dalam snapshot dan menandai semua fungsi Composable yang membaca variabel State ini sebagai memerlukan rekomposisi. Proses ini terjadi secara sinkron dalam satu siklus snapshot, yang menghilangkan status antara saat perubahan berantai.

Parameter policy — argumen kedua dari mutableStateOf, yang menentukan perilaku saat perbandingan. structuralEquality() memeriksa equals() — ini adalah perilaku default. referentialEquality() memeriksa === (kesetaraan referensial). neverEqual() menganggap setiap penugasan sebagai perubahan. Pemilihan policy memengaruhi apakah rekomposisi akan dimulai saat menetapkan nilai yang sama.

Sintaksis dan cara mendeklarasikan mutableStateOf

Cara paling sederhana untuk mendeklarasikan status yang dapat diamati adalah menggunakan mutableStateOf dengan remember. Tanpa remember, setiap rekomposisi akan membuat State baru dan semua perubahan sebelumnya akan hilang. remember menjamin bahwa MutableState yang sama bertahan melalui serangkaian rekomposisi selama fungsi Composable tetap dalam komposisi.

kotlin
@Composable
fun Counter() {
    // Tanpa delegasi: membaca/menulis melalui .value
    val count = remember { mutableStateOf(0) }
    Button(onClick = { count.value++ }) {
        Text("Count: ${count.value}")
    }
}

@Composable
fun CounterDelegated() {
    // Dengan delegasi: var + by = Property Delegation
    var count by remember { mutableStateOf(0) }
    Button(onClick = { count++ }) {
        Text("Count: $count")
    }
}

Perbedaan antara kedua varian bersifat sintaksis. Property Delegation (by) menggunakan konvensi Kotlin: kompiler menghasilkan panggilan getValue() dan setValue() untuk membaca dan menulis. Ini setara dengan akses langsung ke count.value, tetapi terlihat seperti bekerja dengan variabel biasa. Kedua varian secara fungsional identik: Compose melacak pembacaan di getter dan penulisan di setter terlepas dari bentuk penulisan.

BentukKodeMembacaMenulis
Tanpa delegasival count = mutableStateOf(0)count.valuecount.value = n
Dengan delegasivar count by mutableStateOf(0)countcount = n

Properti yang didelegasikan dan var

Mekanisme properti yang didelegasikan Kotin bukanlah fitur Compose, melainkan kemampuan bawaan bahasa. Kelas apa pun dapat mengimplementasikan operator getValue(thisRef, property) dan setValue(thisRef, property, value), setelah itu instance-nya dapat digunakan dengan kata kunci by. MutableState bekerja persis seperti ini: getValue mengembalikan nilai saat ini, dan setValue menetapkan nilai baru.

Perbedaan penting: val dan var. mutableStateOf dapat ditetapkan ke val maupun var. Dalam kasus val (val count = mutableStateOf(0)), objek MutableState itu sendiri tidak dapat diubah, tetapi properti value-nya dapat diubah. Dalam kasus var (var count by mutableStateOf(0)), delegasi menciptakan ilusi bekerja dengan primitif, tetapi sebenarnya setter memanggil setValue pada MutableState. Pilihan antara val dan var adalah pilihan antara akses eksplisit dan implisit ke .value.

State Delegation adalah gula sintaksis yang menyederhanakan kode, tetapi tidak mengubah mekanika. Kompiler Kotlin mentranspilasi var x by mutableStateOf(0) menjadi getter/setter yang memanggil mutableStateOf.getValue() dan mutableStateOf.setValue(). Dalam bytecode yang dihasilkan, tidak ada perbedaan antara val dan var dengan by — keduanya bekerja melalui wadah MutableState yang sama.

kotlin
    // Delegasi kustom untuk State Compose
class ValidatedState<T>(initialValue: T) {
    private val state = mutableStateOf(initialValue)

    operator fun getValue(thisRef: Any?, property: KProperty<*>) = state.value

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        if (value != state.value) {
            state.value = value
        }
    }
}

@Composable
fun Test() {
    var text by remember { ValidatedState("") }
}

Sistem Snapshot: cara kerja mutableStateOf di dalam

Snapshot adalah mekanisme Compose Runtime yang menjamin konsistensi pembacaan State saat perubahan paralel. Ketika fungsi Composable membaca mutableStateOf, snapshot mencatat nilai saat ini. Jika selama komposisi perubahan lain menulis ke State yang sama, snapshot melihat penulisan tetapi tidak mengizinkan pembacaan data yang tidak konsisten — pembacaan selalu mengembalikan nilai yang terkini pada saat snapshot dimulai.

Saat setter mutableStateOf.value = newValue dipanggil, Compose Runtime tidak segera memulai rekomposisi. Sebagai gantinya, perubahan dicatat dalam snapshot saat ini. Ketika snapshot diterapkan (di batas frame), Compose menelusuri daftar State yang diubah dan menandai komponen yang membaca sebagai Invalid. Hanya di frame berikutnya rekomposisi dimulai. Ini menjamin bahwa UI tidak digambar ulang puluhan kali saat perubahan berantai.

Snapshot global dan lokal: secara default mutableStateOf bekerja dalam snapshot global yang diterapkan secara otomatis. Snapshot lokal dapat dibuat melalui Snapshot.takeSnapshot() untuk pembacaan terisolasi tanpa efek samping. Ini digunakan di dalam Modifier, di mana State perlu dibaca tetapi tidak perlu berlangganan perubahan. Pendekatan ini mengoptimalkan kinerja dan mencegah rekomposisi yang tidak terduga.

Contoh penggunaan mutableStateOf

Mari kita lihat skenario nyata — formulir login dengan tiga bidang: email, kata sandi, dan status pemuatan. Ketiga bidang menggunakan mutableStateOf, tetapi dengan policy dan tingkatan bersarang yang berbeda. email menggunakan delegasi, kata sandi — akses langsung.

kotlin
data class LoginState(
    val email: String = "",
    val password: String = "",
    val isLoading: Boolean = false,
    val error: String? = null
)

@Composable
fun LoginForm(onLogin: (String, String) -> Unit) {
    // State tunggal untuk formulir, policy = referentialEquality
    var formState by remember {
        mutableStateOf(LoginState(), SnapshotMutationPolicy.referentialEquality())
    }

    val isValid = remember(formState) {
        formState.email.contains("@") && formState.password.length() >= 6
    }

    Column(modifier = Modifier.padding(16.dp)) {
        OutlinedTextField(
            value = formState.email,
            onValueChange = { formState = formState.copy(email = it) },
            label = { Text("Email") }
        )
        OutlinedTextField(
            value = formState.password,
            onValueChange = { formState = formState.copy(password = it) },
            label = { Text("Kata Sandi") },
            visualTransformation = PasswordVisualTransformation()
        )
        Button(
            onClick = { onLogin(formState.email, formState.password) },
            enabled = isValid
        ) {
            Text("Masuk")
        }
    }
}

Dalam contoh ini, mutableStateOf digunakan dengan kelas data kustom LoginState dan policy referentialEquality. Ini berarti rekomposisi hanya akan dimulai saat instance baru LoginState ditetapkan melalui copy(). isValid dihitung berdasarkan formState dan hanya dihitung ulang saat berubah. Pendekatan ini memberikan kontrol yang jelas atas rekomposisi: setiap bidang formulir hanya berubah dengan membuat salinan baru.

Pertanyaan yang Sering Diajukan

Apa perbedaan mutableStateOf dengan StateFlow?

mutableStateOf adalah wadah khusus Compose yang bekerja di dalam snapshot. StateFlow berasal dari kotlinx.coroutines.flow dan tidak terikat pada Compose. mutableStateOf secara otomatis memulai rekomposisi, StateFlow memerlukan collectAsState(). Untuk status UI di dalam Composable, mutableStateOf lebih disukai.

Bisakah mutableStateOf digunakan di luar fungsi @Composable?

Ya, mutableStateOf dapat dipanggil di luar fungsi Composable, tetapi tidak akan dilacak. Untuk reaktivitas di UI, State harus dibaca di dalam Composable. Banyak ViewModel menggunakan MutableStateField (pembungkus di atas mutableStateOf) untuk mengirim status ke UI melalui StateFlow.

Apa yang terjadi jika State diubah secara bersamaan dari dua thread?

Snapshot sistem menjamin konsistensi: setiap rekomposisi melihat status yang konsisten pada saat snapshot dimulai. Perubahan dari thread yang berbeda diterapkan secara atomik di batas frame, yang menghilangkan race condition saat pembacaan dalam satu komposisi.

Bagaimana cara mereset mutableStateOf ke nilai awal?

Tetapkan nilai baru: count.value = 0 (atau count = 0 dengan delegasi). Jika perlu pembuatan ulang State secara lengkap — gunakan remember dengan kunci: remember(key) { mutableStateOf(initial) } — saat kunci berubah, State akan dibuat ulang.

Apakah mutableStateOf memengaruhi kinerja saat perubahan sering?

Composer menggunakan snapshot yang mengelompokkan perubahan: bahkan dengan seratus penugasan dalam satu frame, rekomposisi hanya dilakukan satu kali. Untuk pembaruan yang sangat sering (animasi), gunakan Animatable atau animate*AsState — keduanya dioptimalkan untuk pembaruan per frame.

Kesimpulan

  • mutableStateOf membuat wadah MutableState yang dapat diamati dan dilacak oleh Compose Runtime
  • Delegasi melalui by menyederhanakan kode, tetapi tidak mengubah mekanika State
  • Snapshot sistem menjamin konsistensi pembacaan dan mencegah rekomposisi yang tidak perlu
  • Policy menentukan kapan perubahan dianggap signifikan — structuralEquality, referentialEquality, neverEqual
  • remember wajib untuk mempertahankan State di antara rekomposisi di dalam Composable
  • Rekomendasi: gunakan mutableStateOf dengan delegasi untuk status UI dan referentialEquality untuk kelas data
  • Hindari: membuat mutableStateOf tanpa remember — setiap penugasan akan membuat objek baru

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga