State Hoisting — ay isang pattern sa Jetpack Compose kung saan ang state ay inilalabas mula sa child na Composable function papunta sa parent, at ang child ay tumatanggap ng data sa pamamagitan ng mga parameter at nagpapaalam ng mga pagbabago sa pamamagitan ng mga callback. Ito ay isang implementasyon ng prinsipyo ng unidirectional na daloy ng data (UDF), kung saan ang state ay itinataas pataas, at ang mga event ay bumababa. Ayon sa Google Android Developers, 2026, ginagawa ng State Hoisting ang mga component na magagamit muli, masusuri, at mahuhulaan.
Mga Pangunahing Punto
State Hoisting (pag-angat ng state) — ay isang pattern kung saan ang Composable function ay hindi nagmamay-ari ng state, bagkus ay natatanggap ito mula sa labas. Sa halip na var sa loob ng function, dalawang parameter ang ginagamit: ang halaga para sa pagpapakita at isang lambda-callback para sa paghawak ng mga pagbabago. Sa teknikal, ito ay nangangahulugan na ang child component ay nagiging stateless (walang sariling state), at ang parent ay nagiging stateful (nagmamay-ari ng state).
Halimbawa: ang TextField component mula sa Material3 ay hindi nag-iimbak ng inilagay na teksto sa loob nito. Tumatanggap ito ng value: String at onValueChange: (String) -> Unit. Ang parent na tumatawag sa TextField ay nagdedeklara ng var value by remember { mutableStateOf("") } at ipinapasa ang value at onValueChange. Ito ay klasikong State Hoisting: TextField — simpleng component (nagpapakita lamang at nag-uulat ng input), parent — matalino (nagmamay-ari ng state).
Stateless vs Stateful: Ang Stateless component ay mas madaling subukan — hindi ito nakadepende sa panloob na state, ang pag-uugali nito ay ganap na tinutukoy ng mga input parameter. Ang Stateful component ay maginhawa para sa mabilis na prototyping, ngunit mas mahirap gamitin muli — ito ay mahigpit na nakatali sa isang source ng data. Ang State Hoisting ay nagbibigay ng pagpipilian: anumang component ay maaaring gawing stateless sa pamamagitan ng paglipat ng state pataas.
UDF (Unidirectional Data Flow) — ay isang prinsipyong arkitektural kung saan ang data ay gumagalaw sa isang direksyon: mula sa pinagmumulan ng katotohanan (ViewModel o parent Composable) patungo sa UI, at ang mga event ay sa kabaligtarang direksyon. Ang State Hoisting ay ang implementasyon ng UDF sa antas ng mga indibidwal na component. Sa halip na ang bawat component ay magpasya nang mag-isa kung kailan at paano baguhin ang state nito, ito ay nag-uulat ng event sa parent, at ang parent ang nagpapasya kung paano baguhin ang state.
Mga bentahe ng UDF: prediktabilidad — ang state ay nagbabago lamang sa isang lugar, na nag-aalis ng race conditions; traceability — sa pamamagitan ng call stack ay maaaring muling buuin ang chain ng mga pagbabago; pagsubok — ang stateful na lohika ay maaaring ilipat sa isang hiwalay na klase at subukan nang walang UI. Sa malalaking proyekto, ang UDF na sinamahan ng State Hoisting ay isang de facto na pamantayan.
Nag-iisang Pinagmumulan ng Katotohanan (Single Source of Truth) — isa pang prinsipyong kasama ng UDF. Ang bawat fragment ng state ay may eksaktong isang pinagmumulan. Kung dalawang component ang gumagamit ng parehong state, ang pinagmumulan ay dapat na magkasama (sa antas ng ViewModel o karaniwang parent). Ginagarantiyahan ng State Hoisting na ang pinagmumulan ay mas mataas sa hierarchy at walang pagdodoble ng state na nagaganap.
| Direksyon | Ano ang ipinapasa | Paano ipinatupad |
|---|---|---|
| Pababa (parent → child) | Halaga para sa pagpapakita | Parametro value: T |
| Pataas (child → parent) | Event ng pagbabago | Parametro onValueChange: (T) -> Unit |
Pangunahing panuntunan: ang state ay dapat itaas sa pinakamababang posibleng antas na sapat para sa lahat ng component na nangangailangan nito. Kung ang state ay ginagamit lamang sa loob ng isang component — panatilihin itong lokal. Kung dalawang magkalapit na component ay nangangailangan ng parehong state — itaas ito sa karaniwang parent. Kung ang state ay kailangan sa buong screen — itaas ito sa ViewModel.
Panuntunan ng minimal na pag-angat ay pumipigil sa hindi kinakailangang komplikasyon. Walang saysay na itaas ang state ng isang text field sa ViewModel kung ito ay ginagamit lamang sa loob ng isang screen at hindi nai-save kapag muling ginawa ang Activity. Gamitin ang rememberSaveable sa antas ng parent ng screen, hindi ViewModel, para sa UI state na dapat mabuhay sa pag-ikot ng screen ngunit hindi kailangan ng lohika ng negosyo.
Kailan itataas sa ViewModel: kung ang state ay dapat mapanatili kapag muling ginawa ang Activity, kung ito ay kailangan ng maraming screen, kung ang pagbabago ng state ay nag-trigger ng lohika ng negosyo (mga network request, database). Ang State Hoisting sa antas ng ViewModel ay isang tipikal na pattern sa arkitekturang MVVM, kung saan ang UI layer ay stateless at ang ViewModel ay stateful.
// ❌ Masama: ang component ay nagmamay-ari ng sarili nitong state
@Composable
fun BadTextField(label: String) {
var text by remember { mutableStateOf("") }
TextField(value = text, onValueChange = { text = it }, label = { Text(label) })
}
// ✅ Mabuti: State Hoisting — state sa parent
@Composable
fun GoodTextField(value: String, onValueChange: (String) -> Unit, label: String) {
TextField(value = value, onValueChange = onValueChange, label = { Text(label) })
}
// Paggamit: ang parent ay nagmamay-ari ng state
@Composable
fun Form() {
var name by rememberSaveable { mutableStateOf("") }
GoodTextField(value = name, onValueChange = { name = it }, label = "Name")
}
Isaalang-alang ang login screen na may dalawang field (email, password) at isang button. Lahat ng tatlong component ay tumatanggap ng state sa pamamagitan ng State Hoisting: ang email at password ay pinamamahalaan ng parent, ang button ay tumatanggap ng enabled status bilang halaga.
// State Hoisting sa antas ng screen
@Composable
fun LoginScreen(viewModel: LoginViewModel) {
val uiState by viewModel.uiState.collectAsState()
Column(modifier = Modifier.padding(16.dp)) {
// Email field — State Hoisting sa pamamagitan ng lambda
EmailField(
email = uiState.email,
onEmailChange = { viewModel.onEmailChanged(it) }
)
// Password field — katulad
PasswordField(
password = uiState.password,
onPasswordChange = { viewModel.onPasswordChanged(it) }
)
// Button — tumatanggap lamang ng enabled (read-only)
LoginButton(enabled = uiState.isFormValid, onClick = viewModel::login)
}
}
// Stateless component: tumatanggap ng email + callback
@Composable
fun EmailField(email: String, onEmailChange: (String) -> Unit) {
OutlinedTextField(
value = email,
onValueChange = onEmailChange,
label = { Text("Email") },
singleLine = true
)
}
// Stateless button component
@Composable
fun LoginButton(enabled: Boolean, onClick: () -> Unit) {
Button(onClick = onClick, enabled = enabled) {
Text("Mag-login")
}
}
EmailField at PasswordField — ganap na stateless. Maaari silang magamit muli sa anumang screen, na konektado sa anumang mapagkukunan ng data. Ang LoginButton ay tumatanggap ng enabled bilang read-only — ito ay isa pang anyo ng State Hoisting kung saan ang state ay hindi itinataas (ang button ay hindi maaaring i-enable ang sarili nito), bagkus ay ipinapasa nang handa. Ang pamamaraang ito ay nagbibigay ng maximum na flexibility na may minimal na pagkakabit ng component.
Hindi lahat ng state ay kailangang itaas. Ang lokal na state (State sa loob ng Composable) ay makatwiran kapag: ang data ay kailangan lamang sa loob ng isang component, hindi ito nakakaapekto sa mga kalapit na elemento, hindi ito dapat mabuhay sa recomposition ng isang partikular na seksyon. Halimbawa, ang estado ng animation, focus ng input field, kasalukuyang posisyon ng scroll — makatuwirang panatilihing lokal.
Kailan kailangan ang State Hoisting: ang state ay ginagamit ng maraming child component; ang pagbabago sa isang child ay dapat na maipakita sa isa pa; kailangang subukan ang lohika ng pagbabago ng state nang hiwalay sa UI; ang state ay dapat mapanatili kapag muling ginawa ang Activity. Sa mga kasong ito, ang lokal na state ay lumilikha ng pagdodoble at hindi pagkakatugma ng data.
Hybrid na pamamaraan: panatilihin ang minimal na state nang lokal, itaas ang natitira. Ang panuntunan ng Compose: “itaas ang state nang kasingtaas ng kinakailangan at kasingbaba ng posible”. Sa praktika, ito ay nangangahulugang magsimula sa lokal na remember, at kapag lumitaw ang pangangailangan para sa access mula sa ibang component — itaas ang antas. Huwag gawin ang State Hoisting nang preventive — pinapakomplikado nito ang code nang hindi kinakailangan.
Mga Madalas Itanong
State Hoisting — ay isang pattern sa antas ng UI component. ViewModel — ay isang arkitektural na layer para sa lohika ng negosyo. Maaaring itaas ng State Hoisting ang state sa antas ng parent Composable, sa antas ng screen, o sa ViewModel. ViewModel — ay ang pinakamataas na punto ng pag-angat para sa state na dapat mabuhay sa muling paggawa ng Activity.
Ang stateless component ay sinusubukan sa pamamagitan ng simpleng pagpapasa ng mga halaga. Tawagan ang Composable gamit ang mga kinakailangang parameter at suriin ang pagpapakita sa pamamagitan ng ComposeTestRule. Ang pagbabago ng state ay sinusubukan sa antas ng parent o ViewModel — hiwalay sa UI. Ito ay lubos na nagpapasimple sa mga pagsubok: hindi kailangang gayahin ang recomposition sa loob ng component.
Oo, ito ay karaniwang praktika. Kung ang component ay kailangan lamang magpakita ng data nang walang kakayahang baguhin ang mga ito — ipasa ang State<T> (read-only). Ang component ay mag-subscribe sa mga pagbabago, ngunit hindi magagawang simulan ang mga ito. Pinapalakas nito ang encapsulation at pinoprotektahan ang data mula sa hindi kanais-nais na mga mutation.
Para sa malalim na pagpapasa, gamitin ang CompositionLocal o pagpapasa sa pamamagitan ng mga parameter ng parent Composable. Kung ang state ay kailangan sa buong screen — ilipat ito sa ViewModel at gamitin ang collectAsState(). Ang pagpapasa sa pamamagitan ng 5+ na antas ay tanda ng maling arkitektura; suriin muli ang hierarchy ng component.
State Hoisting ay maaaring bahagyang tumaas ang bilang ng mga recomposition, dahil ang pagbabago sa parent ay maaaring mag-recompose ng lahat ng child. Gamitin ang derivedStateOf para sa pagsala ng mga pagbabago at keys sa LazyColumn para sa mga puntong update. Sa karamihan ng mga sitwasyon, ang overhead ng State Hoisting ay bale-wala kumpara sa mga benepisyo ng maintainability.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din