mutableStateOf: ایجاد حالت قابل مشاهده و واکنش‌پذیری Compose

نویسنده: IT Sectr منتشر شده: 2026-06-28 زمان مطالعه: 7 دقیقه

mutableStateOf تابعی در Jetpack Compose است که یک ظرف حالت قابل مشاهده متغیر ایجاد می‌کند. وقتی مقدار داخل این ظرف تغییر می‌کند، Compose به طور خودکار بازترکیب تمام اجزایی که این حالت را می‌خوانند آغاز می‌کند. بدون mutableStateOf، UI نمی‌توانست هنگام تغییرات داده‌ها به صورت واکنشی به‌روزرسانی شود. به گفته Google Android Developers، 2026، mutableStateOf بلوک ساختمانی اصلی برای حالت محلی در Compose است.

نکات کلیدی

  • mutableStateOf یک ظرف MutableState ایجاد می‌کند که توسط Compose Runtime ردیابی می‌شود
  • بازترکیب به طور خودکار هنگام تغییر value این شیء State آغاز می‌شود
  • تفویض از طریق var امکان استفاده از mutableStateOf بدون مراجعه به .value را فراهم می‌کند
  • کلیدها در remember(mutableStateOf) مورد نیاز نیستند — State خودش Compose را از تغییرات مطلع می‌کند
  • سیستم Snapshot سازگاری خواندن در محیط چندنخی را تضمین می‌کند

mutableStateOf در Jetpack Compose چیست

mutableStateOf تابعی از بسته compose.runtime است که یک شیء MutableState<T> ایجاد می‌کند و مقداری را ذخیره می‌کند و می‌تواند Compose Runtime را از تغییرات مطلع کند. امضا: fun <T> mutableStateOf(value: T, policy: SnapshotMutationPolicy<T> = structuralEquality()): MutableState<T>. پارامتر policy تعیین می‌کند که چه زمانی تغییر معنی‌دار تلقی می‌شود — در برابری ساختاری، برابری ارجاعی یا هرگز.

MutableState یک رابط با یک ویژگی value است: getter برای خواندن و setter برای نوشتن. هنگام فراخوانی setter، Compose Runtime تغییر را در snapshot ثبت می‌کند و تمام توابع Composable که این متغیر State را می‌خوانند به عنوان نیازمند بازترکیب علامت‌گذاری می‌کند. این فرآیند به صورت همزمان در یک چرخه snapshot انجام می‌شود که حالت‌های میانی را در تغییرات آبشاری حذف می‌کند.

Parameter policy — دومین آرگومان mutableStateOf، که رفتار هنگام مقایسه را تعیین می‌کند. structuralEquality() equals() را بررسی می‌کند — این رفتار پیش‌فرض است. referentialEquality() === (برابری ارجاعی) را بررسی می‌کند. neverEqual() هر انتساب را تغییر تلقی می‌کند. انتخاب policy بر این تأثیر می‌گذارد که آیا بازترکیب هنگام انتساب مقدار یکسان آغاز می‌شود یا خیر.

نحو و روش‌های اعلان mutableStateOf

ساده‌ترین راه برای اعلان حالت قابل مشاهده استفاده از mutableStateOf با remember است. بدون remember در هر بازترکیب یک State جدید ایجاد می‌شد و تمام تغییرات قبلی از دست می‌رفت. remember تضمین می‌کند که همان MutableState در یک سری بازترکیب باقی می‌ماند تا زمانی که تابع Composable در ترکیب باقی بماند.

kotlin
@Composable
fun Counter() {
    // بدون تفویض: خواندن/نوشتن از طریق .value
    val count = remember { mutableStateOf(0) }
    Button(onClick = { count.value++ }) {
        Text("Count: ${count.value}")
    }
}

@Composable
fun CounterDelegated() {
    // با تفویض: var + by = Property Delegation
    var count by remember { mutableStateOf(0) }
    Button(onClick = { count++ }) {
        Text("Count: $count")
    }
}

تفاوت بین دو روش نحوی است. Property Delegation (by) از قرارداد Kotlin استفاده می‌کند: کامپایلر فراخوانی‌های getValue() و setValue() را برای خواندن و نوشتن تولید می‌کند. این معادل مراجعه مستقیم به count.value است، اما مانند کار با یک متغیر معمولی به نظر می‌رسد. هر دو روش از نظر عملکردی یکسان هستند: Compose خواندن در getter و نوشتن در setter را بدون توجه به شکل نوشتار ردیابی می‌کند.

شکلکدخواندننوشتن
بدون تفویضval count = mutableStateOf(0)count.valuecount.value = n
با تفویضvar count by mutableStateOf(0)countcount = n

ویژگی‌های تفویض شده و var

مکانیزم ویژگی‌های تفویض شده Kotlin یک ویژگی Compose نیست، بلکه یک قابلیت داخلی زبان است. هر کلاسی می‌تواند عملگرهای getValue(thisRef, property) و setValue(thisRef, property, value) را پیاده‌سازی کند، پس از آن نمونه آن می‌تواند با کلمه کلیدی by استفاده شود. MutableState دقیقاً به این صورت کار می‌کند: getValue مقدار فعلی را برمی‌گرداند و setValue مقدار جدید را انتساب می‌دهد.

تفاوت مهم: val و var. mutableStateOf را می‌توان هم به val و هم به var اختصاص داد. در مورد val (val count = mutableStateOf(0)) خود شیء MutableState تغییرناپذیر است، اما ویژگی value آن قابل تغییر است. در مورد var (var count by mutableStateOf(0)) تفویض توهم کار با یک نوع ابتدایی را ایجاد می‌کند، اما در واقعیت setter متد setValue را روی MutableState فراخوانی می‌کند. انتخاب بین val و var انتخابی بین دسترسی صریح و ضمنی به .value است.

State Delegation شکر نحوی است که کد را ساده‌تر می‌کند اما مکانیک را تغییر نمی‌دهد. کامپایلر Kotlin var x by mutableStateOf(0) را به getter/setter تبدیل می‌کند که mutableStateOf.getValue() و mutableStateOf.setValue() را فراخوانی می‌کنند. در بایت کد تولید شده، تفاوتی بین val و var با by وجود ندارد — هر دو از طریق همان ظرف MutableState کار می‌کنند.

kotlin
    // تفویض سفارشی برای 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("") }
}

سیستم Snapshot: mutableStateOf در داخل چگونه کار می‌کند

Snapshot مکانیزم Compose Runtime است که سازگاری خواندن State را در تغییرات همزمان تضمین می‌کند. وقتی تابع Composable mutableStateOf را می‌خواند، snapshot مقدار فعلی را ثبت می‌کند. اگر در طول ترکیب تغییر دیگری در همان State بنویسد، snapshot نوشتن را می‌بیند اما اجازه خواندن داده‌های ناسازگار را نمی‌دهد — خواندن همیشه مقداری را برمی‌گرداند که در لحظه شروع snapshot به‌روز است.

هنگام فراخوانی setter mutableStateOf.value = newValue، Compose Runtime بلافاصله بازترکیب را آغاز نمی‌کند. در عوض، تغییر در snapshot فعلی ثبت می‌شود. وقتی snapshot اعمال می‌شود (در مرز فریم)، Compose از لیست Stateهای تغییر یافته عبور می‌کند و اجزای خواننده را به عنوان Invalid علامت‌گذاری می‌کند. فقط در فریم بعدی بازترکیب آغاز می‌شود. این تضمین می‌کند که UI در تغییرات آبشاری ده‌ها بار دوباره ترسیم نشود.

Snapshot‌های سراسری و محلی: به طور پیش‌فرض mutableStateOf در snapshot سراسری کار می‌کند که به طور خودکار اعمال می‌شود. می‌توان یک snapshot محلی از طریق Snapshot.takeSnapshot() برای خواندن ایزوله بدون عوارض جانبی ایجاد کرد. این در داخل Modifier استفاده می‌شود، جایی که نیاز به خواندن State است اما نیازی به اشتراک در تغییرات نیست. این رویکرد عملکرد را بهینه می‌کند و از بازترکیب‌های غیرمنتظره جلوگیری می‌کند.

مثال‌های استفاده از mutableStateOf

یک سناریوی واقعی را در نظر بگیرید — فرم ورود با سه فیلد: ایمیل، رمز عبور و وضعیت بارگذاری. هر سه فیلد از mutableStateOf استفاده می‌کنند، اما با policy و تودرتویی متفاوت. ایمیل از تفویض استفاده می‌کند، رمز عبور — دسترسی مستقیم.

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 واحد برای فرم، 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("ایمیل") }
        )
        OutlinedTextField(
            value = formState.password,
            onValueChange = { formState = formState.copy(password = it) },
            label = { Text("رمز عبور") },
            visualTransformation = PasswordVisualTransformation()
        )
        Button(
            onClick = { onLogin(formState.email, formState.password) },
            enabled = isValid
        ) {
            Text("ورود")
        }
    }
}

در این مثال mutableStateOf با یک کلاس داده سفارشی LoginState و policy referentialEquality استفاده شده است. این بدان معناست که بازترکیب فقط هنگام انتساب یک نمونه جدید LoginState از طریق copy() آغاز می‌شود. isValid بر اساس formState محاسبه می‌شود و فقط هنگام تغییر آن دوباره محاسبه می‌شود. این رویکرد کنترل دقیقی بر بازترکیب‌ها می‌دهد: هر فیلد فرم فقط با ایجاد یک کپی جدید تغییر می‌کند.

سوالات متداول

mutableStateOf چه تفاوتی با StateFlow دارد؟

mutableStateOf یک ظرف مخصوص Compose است که در داخل snapshot‌ها کار می‌کند. StateFlow از kotlinx.coroutines.flow است که به Compose وابسته نیست. mutableStateOf به طور خودکار بازترکیب را آغاز می‌کند، StateFlow نیاز به collectAsState() دارد. برای حالت UI داخل Composable، mutableStateOf ترجیح داده می‌شود.

آیا می‌توان از mutableStateOf خارج از توابع @Composable استفاده کرد؟

بله، mutableStateOf را می‌توان خارج از تابع Composable فراخوانی کرد، اما ردیابی نخواهد شد. برای کارکرد واکنش‌پذیری در UI باید State را داخل Composable بخوانید. بسیاری از ViewModel‌ها از MutableStateField (پوششی بر روی mutableStateOf) برای ارسال حالت به UI از طریق StateFlow استفاده می‌کنند.

هنگام تغییر همزمان State از دو رشته چه اتفاقی می‌افتد؟

Snapshot سیستم سازگاری را تضمین می‌کند: هر بازترکیب حالت سازگاری را در لحظه شروع snapshot می‌بیند. تغییرات از رشته‌های مختلف به صورت اتمی در مرز فریم اعمال می‌شوند که race condition را هنگام خواندن در یک ترکیب حذف می‌کند.

چگونه mutableStateOf را به مقدار اولیه بازنشانی کنیم؟

یک مقدار جدید انتساب دهید: count.value = 0 (یا count = 0 در صورت تفویض). اگر نیاز به بازآفرینی کامل State است — از remember با کلید استفاده کنید: remember(key) { mutableStateOf(initial) } — با تغییر کلید State دوباره ایجاد می‌شود.

آیا mutableStateOf بر عملکرد در تغییرات مکرر تأثیر می‌گذارد؟

Composer از snapshot‌ها استفاده می‌کند که تغییرات را گروه‌بندی می‌کنند: حتی با صد انتساب در یک فریم، بازترکیب فقط یک بار انجام می‌شود. برای به‌روزرسانی‌های بسیار مکرر (انیمیشن‌ها) از Animatable یا animate*AsState استفاده کنید — آنها برای به‌روزرسانی فریم بهینه شده‌اند.

خلاصه

  • mutableStateOf یک ظرف قابل مشاهده MutableState ایجاد می‌کند که توسط Compose Runtime ردیابی می‌شود
  • تفویض از طریق by کد را ساده‌تر می‌کند اما مکانیک State را تغییر نمی‌دهد
  • Snapshot سیستم سازگاری خواندن را تضمین می‌کند و از بازترکیب‌های اضافی جلوگیری می‌کند
  • Policy تعیین می‌کند چه زمانی تغییر معنی‌دار تلقی می‌شود — structuralEquality، referentialEquality، neverEqual
  • remember برای حفظ State بین بازترکیب‌ها داخل Composable اجباری است
  • توصیه: از mutableStateOf با تفویض برای حالت UI و referentialEquality برای کلاس‌های داده استفاده کنید
  • اجتناب کنید: ایجاد mutableStateOf بدون remember — هر انتساب یک شیء جدید ایجاد می‌کند

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید