mutableStateOf: การสร้างสถานะที่สังเกตได้และการตอบสนองของ Compose

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-06-28 เวลาอ่าน: 7 นาที

mutableStateOf เป็นฟังก์ชันใน Jetpack Compose ที่สร้างคอนเทนเนอร์สถานะที่เปลี่ยนแปลงได้และสังเกตได้ เมื่อค่าภายในคอนเทนเนอร์นี้เปลี่ยนแปลง Compose จะเริ่มการประกอบใหม่ของคอมโพเนนต์ทั้งหมดที่อ่านสถานะนี้โดยอัตโนมัติ หากไม่มี mutableStateOf ส่วนติดต่อผู้ใช้จะไม่สามารถอัปเดตแบบตอบสนองเมื่อข้อมูลเปลี่ยนแปลงได้ ตาม 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 เดียว ซึ่งกำจัดสถานะกลางระหว่างการเปลี่ยนแปลงแบบลูกโซ่

พารามิเตอร์ 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
    // ผู้รับมอบหมายที่กำหนดเองสำหรับ Compose State
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 เฉพาะในเฟรมถัดไปเท่านั้นที่การประกอบใหม่จะเริ่มขึ้น ซึ่งรับประกันว่าส่วนติดต่อผู้ใช้จะไม่ถูกวาดใหม่หลายสิบครั้งระหว่างการเปลี่ยนแปลงแบบลูกโซ่

Snapshot ระดับโลกและระดับท้องถิ่น: โดยค่าเริ่มต้น mutableStateOf ทำงานใน snapshot ระดับโลกซึ่งถูกนำไปใช้โดยอัตโนมัติ คุณสามารถสร้าง snapshot ระดับท้องถิ่นผ่าน Snapshot.takeSnapshot() สำหรับการอ่านแบบแยกโดยไม่มีผลข้างเคียง ซึ่งใช้ภายใน Modifier เมื่อคุณต้องการอ่าน State โดยไม่สมัครรับการเปลี่ยนแปลง แนวทางนี้ปรับปรุงประสิทธิภาพและป้องกันการประกอบใหม่ที่ไม่คาดคิด

ตัวอย่างการใช้งาน mutableStateOf

ลองพิจารณาสถานการณ์จริง — ฟอร์มเข้าสู่ระบบที่มีสามฟิลด์: อีเมล รหัสผ่าน และสถานะการโหลด ทั้งสามฟิลด์ใช้ mutableStateOf แต่มี policy และระดับการซ้อนที่แตกต่างกัน email ใช้การมอบหมาย password ใช้การเข้าถึงโดยตรง

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 ได้ แต่จะไม่ถูกติดตาม สำหรับการตอบสนองในส่วนติดต่อผู้ใช้ ต้องอ่าน State ภายใน Composable ViewModel หลายตัวใช้ MutableStateField (ตัวห่อรอบ mutableStateOf) เพื่อส่งสถานะไปยังส่วนติดต่อผู้ใช้ผ่าน StateFlow

จะเกิดอะไรขึ้นเมื่อ State ถูกเปลี่ยนแปลงพร้อมกันจากสองเธรด

ระบบ Snapshot รับประกันความสอดคล้อง: การประกอบใหม่แต่ละครั้งเห็นสถานะที่สอดคล้องกัน ณ จุดเริ่มต้นของ snapshot การเปลี่ยนแปลงจากเธรดต่าง ๆ ถูกนำไปใช้แบบอะตอมมิกที่ขอบเขตเฟรม กำจัดสภาวะการแข่งระหว่างการอ่านภายในองค์ประกอบเดียว

วิธีรีเซ็ต 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 สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม