State Hoisting Jetpack Compose में एक पैटर्न है जिसमें स्थिति को चाइल्ड Composable फ़ंक्शन से पैरेंट में निकाला जाता है, और चाइल्ड पैरामीटर के माध्यम से डेटा प्राप्त करता है और कॉलबैक के माध्यम से परिवर्तनों की सूचना देता है। यह एकदिश डेटा प्रवाह (UDF) सिद्धांत का कार्यान्वयन है, जिसमें स्थिति ऊपर उठती है और घटनाएँ नीचे आती हैं। Google Android Developers, 2026 के अनुसार, State Hoisting घटकों को पुन: प्रयोज्य, परीक्षण योग्य और पूर्वानुमेय बनाता है।
मुख्य बातें
State Hoisting एक पैटर्न है जिसमें Composable फ़ंक्शन स्थिति का स्वामी नहीं होता बल्कि उसे बाहर से प्राप्त करता है। फ़ंक्शन के अंदर var के बजाय दो पैरामीटर का उपयोग किया जाता है: प्रदर्शन के लिए एक मान और परिवर्तनों को संभालने के लिए एक लैम्ब्डा कॉलबैक। तकनीकी रूप से, इसका अर्थ है कि चाइल्ड घटक स्टेटलेस (बिना अपनी स्थिति) हो जाता है, जबकि पैरेंट स्टेटफुल (स्थिति का स्वामी) होता है।
उदाहरण: Material3 का TextField घटक आंतरिक रूप से दर्ज टेक्स्ट संग्रहीत नहीं करता। यह value: String और onValueChange: (String) -> Unit स्वीकार करता है। TextField को कॉल करने वाला पैरेंट var value by remember { mutableStateOf("") } घोषित करता है और value और onValueChange पास करता है। यह क्लासिक State Hoisting है: TextField एक डंब घटक है (केवल प्रदर्शित करता है और इनपुट की रिपोर्ट करता है), पैरेंट स्मार्ट है (स्थिति का स्वामी)।
स्टेटलेस बनाम स्टेटफुल: स्टेटलेस घटक का परीक्षण करना आसान है — यह आंतरिक स्थिति पर निर्भर नहीं करता, इसका व्यवहार पूरी तरह से इनपुट पैरामीटर द्वारा निर्धारित होता है। स्टेटफुल घटक तेज़ प्रोटोटाइपिंग के लिए सुविधाजनक है लेकिन पुन: उपयोग करना कठिन है: यह एक डेटा स्रोत से कसकर जुड़ा होता है। State Hoisting आपको विकल्प देता है: स्थिति को ऊपर ले जाकर किसी भी घटक को स्टेटलेस बनाया जा सकता है।
UDF (एकदिश डेटा प्रवाह) एक आर्किटेक्चरल सिद्धांत है जहाँ डेटा एक दिशा में चलता है: सत्य के स्रोत (ViewModel या पैरेंट Composable) से UI तक, और घटनाएँ विपरीत दिशा में प्रवाहित होती हैं। State Hoisting व्यक्तिगत घटक स्तर पर UDF का कार्यान्वयन है। प्रत्येक घटक के अपनी स्थिति को कब और कैसे बदलना है यह तय करने के बजाय, वह पैरेंट को एक घटना के बारे में सूचित करता है, और पैरेंट तय करता है कि स्थिति कैसे बदलनी है।
UDF के लाभ: पूर्वानुमेयता — स्थिति केवल एक स्थान पर बदलती है, जो प्रतिस्पर्धा स्थितियों को समाप्त करती है; ट्रेसेबिलिटी — कॉल स्टैक परिवर्तनों की श्रृंखला को पुनर्निर्मित करने देता है; परीक्षण — स्टेटफुल तर्क को एक अलग वर्ग में निकाला जा सकता है और बिना UI के परीक्षण किया जा सकता है। बड़ी परियोजनाओं में, State Hoisting के साथ UDF वास्तविक मानक है।
सत्य का एकल स्रोत (Single Source of Truth) एक और सिद्धांत है जो UDF के साथ आता है। स्थिति के प्रत्येक टुकड़े का एक ही स्रोत होता है। यदि दो घटक समान स्थिति का उपयोग करते हैं, तो स्रोत साझा होना चाहिए (ViewModel या सामान्य पैरेंट स्तर पर)। State Hoisting सुनिश्चित करता है कि स्रोत पदानुक्रम में ऊपर है और स्थिति का दोहराव नहीं होता है।
| दिशा | क्या पास किया जाता है | कैसे कार्यान्वित किया जाता है |
|---|---|---|
| नीचे (पैरेंट → चाइल्ड) | प्रदर्शित करने के लिए मान | पैरामीटर value: T |
| ऊपर (चाइल्ड → पैरेंट) | परिवर्तन घटना | पैरामीटर onValueChange: (T) -> Unit |
मुख्य नियम: स्थिति को न्यूनतम संभव स्तर तक उठाया जाना चाहिए जो सभी घटकों के लिए पर्याप्त हो जिन्हें इसकी आवश्यकता है। यदि स्थिति केवल एक घटक के अंदर उपयोग की जाती है — इसे स्थानीय रखें। यदि दो आसन्न घटकों को समान स्थिति की आवश्यकता है — इसे सामान्य पैरेंट तक उठाएँ। यदि स्थिति पूरी स्क्रीन पर आवश्यक है — इसे ViewModel तक उठाएँ।
न्यूनतम उत्थान नियम अनावश्यक जटिलता को रोकता है। टेक्स्ट फ़ील्ड स्थिति को ViewModel में उठाने का कोई मतलब नहीं है यदि इसका उपयोग केवल एक स्क्रीन के भीतर किया जाता है और Activity के पुनर्निर्माण पर संग्रहीत नहीं किया जाता है। स्क्रीन पैरेंट स्तर पर rememberSaveable का उपयोग करें, ViewModel में नहीं, UI स्थिति के लिए जो स्क्रीन रोटेशन से बचनी चाहिए लेकिन व्यावसायिक तर्क को इसकी आवश्यकता नहीं है।
ViewModel में कब उठाएँ: यदि स्थिति को Activity पुनर्निर्माण पर बचना चाहिए, यदि कई स्क्रीन को इसकी आवश्यकता है, यदि स्थिति बदलने से व्यावसायिक तर्क (नेटवर्क अनुरोध, डेटाबेस) सक्रिय होता है। ViewModel स्तर पर State Hoisting MVVM आर्किटेक्चर में एक मानक पैटर्न है, जहाँ UI परत स्टेटलेस और ViewModel स्टेटफुल है।
// ❌ बुरा: घटक अपनी स्वयं की स्थिति रखता है
@Composable
fun BadTextField(label: String) {
var text by remember { mutableStateOf("") }
TextField(value = text, onValueChange = { text = it }, label = { Text(label) })
}
// ✅ अच्छा: State Hoisting — स्थिति पैरेंट में
@Composable
fun GoodTextField(value: String, onValueChange: (String) -> Unit, label: String) {
TextField(value = value, onValueChange = onValueChange, label = { Text(label) })
}
// उपयोग: पैरेंट स्थिति का स्वामी है
@Composable
fun Form() {
var name by rememberSaveable { mutableStateOf("") }
GoodTextField(value = name, onValueChange = { name = it }, label = "Name")
}
एक लॉगिन स्क्रीन पर विचार करें जिसमें दो फ़ील्ड (ईमेल, पासवर्ड) और एक बटन है। तीनों घटक State Hoisting के माध्यम से स्थिति प्राप्त करते हैं: ईमेल और पासवर्ड पैरेंट द्वारा प्रबंधित होते हैं, बटन अपनी enabled स्थिति एक मान के रूप में प्राप्त करता है।
// स्क्रीन स्तर पर State Hoisting
@Composable
fun LoginScreen(viewModel: LoginViewModel) {
val uiState by viewModel.uiState.collectAsState()
Column(modifier = Modifier.padding(16.dp)) {
// ईमेल फ़ील्ड — लैम्ब्डा के माध्यम से State Hoisting
EmailField(
email = uiState.email,
onEmailChange = { viewModel.onEmailChanged(it) }
)
// पासवर्ड फ़ील्ड — इसी प्रकार
PasswordField(
password = uiState.password,
onPasswordChange = { viewModel.onPasswordChanged(it) }
)
// बटन — केवल enabled प्राप्त करता है (केवल पढ़ने के लिए)
LoginButton(enabled = uiState.isFormValid, onClick = viewModel::login)
}
}
// स्टेटलेस घटक: ईमेल + कॉलबैक प्राप्त करता है
@Composable
fun EmailField(email: String, onEmailChange: (String) -> Unit) {
OutlinedTextField(
value = email,
onValueChange = onEmailChange,
label = { Text("ईमेल") },
singleLine = true
)
}
// स्टेटलेस बटन घटक
@Composable
fun LoginButton(enabled: Boolean, onClick: () -> Unit) {
Button(onClick = onClick, enabled = enabled) {
Text("लॉगिन")
}
}
EmailField और PasswordField पूरी तरह से स्टेटलेस हैं। इन्हें किसी भी डेटा स्रोत से जोड़कर किसी भी स्क्रीन पर पुन: उपयोग किया जा सकता है। LoginButton enabled को केवल पढ़ने के लिए प्राप्त करता है — यह State Hoisting का एक और रूप है जहाँ स्थिति उठाई नहीं जाती (बटन स्वयं को सक्षम नहीं कर सकता) बल्कि तैयार नीचे भेजी जाती है। यह दृष्टिकोण न्यूनतम घटक युग्मन के साथ अधिकतम लचीलापन प्रदान करता है।
हर स्थिति को उठाने की आवश्यकता नहीं है। स्थानीय स्थिति (Composable के अंदर State) उचित है जब: डेटा केवल एक घटक के अंदर आवश्यक है, यह पड़ोसी तत्वों को प्रभावित नहीं करता, और इसे किसी विशिष्ट अनुभाग के पुनर्संयोजन से बचना नहीं चाहिए। उदाहरण के लिए, एनिमेशन स्थिति, इनपुट फ़ील्ड फ़ोकस, वर्तमान स्क्रॉल स्थिति — इन्हें स्थानीय रखना उचित है।
State Hoisting कब आवश्यक है: स्थिति कई चाइल्ड घटकों द्वारा उपयोग की जाती है; एक चाइल्ड में परिवर्तन दूसरे में प्रतिबिंबित होना चाहिए; स्थिति परिवर्तनों के तर्क का UI से अलग परीक्षण किया जाना चाहिए; स्थिति को Activity पुनर्निर्माण पर बचना चाहिए। इन मामलों में, स्थानीय स्थिति डेटा दोहराव और असंगति पैदा करती है।
हाइब्रिड दृष्टिकोण: न्यूनतम स्थिति को स्थानीय रखें, बाकी उठाएँ। Compose का नियम: “स्थिति को जितना आवश्यक हो उतना ऊपर और जितना संभव हो उतना नीचे उठाएँ।” व्यवहार में, इसका अर्थ है स्थानीय remember से शुरू करना और केवल तभी स्तर उठाना जब किसी अन्य घटक से पहुँच की आवश्यकता हो। State Hoisting को पूर्व-सक्रिय रूप से न लागू करें — यह बिना आवश्यकता के कोड को जटिल बनाता है।
अक्सर पूछे जाने वाले प्रश्न
State Hoisting UI घटक-स्तरीय पैटर्न है। ViewModel व्यावसायिक तर्क के लिए एक आर्किटेक्चरल परत है। State Hoisting स्थिति को पैरेंट Composable स्तर, स्क्रीन स्तर या ViewModel तक उठा सकता है। ViewModel उस स्थिति के लिए उच्चतम उत्थान बिंदु है जिसे Activity पुनर्निर्माण पर बचना चाहिए।
स्टेटलेस घटक का परीक्षण केवल मान पास करके किया जाता है। आवश्यक पैरामीटर के साथ Composable को कॉल करें और ComposeTestRule के माध्यम से प्रदर्शन की जाँच करें। स्थिति परिवर्तनों का परीक्षण पैरेंट या ViewModel स्तर पर किया जाता है — UI से अलग। यह परीक्षणों को काफी सरल बनाता है: घटक के अंदर पुनर्संयोजन का अनुकरण करने की आवश्यकता नहीं है।
हाँ, यह सामान्य अभ्यास है। यदि किसी घटक को बिना संशोधित करने की क्षमता के केवल डेटा प्रदर्शित करने की आवश्यकता है — State<T> (केवल पढ़ने के लिए) पास करें। घटक परिवर्तनों की सदस्यता लेगा लेकिन उन्हें आरंभ नहीं कर सकेगा। यह एनकैप्सुलेशन को मजबूत करता है और डेटा को अवांछित उत्परिवर्तन से बचाता है।
गहरे पासिंग के लिए CompositionLocal या पैरेंट Composable पैरामीटर के माध्यम से पास करें। यदि पूरी स्क्रीन पर स्थिति आवश्यक है — इसे ViewModel में निकालें और collectAsState() का उपयोग करें। 5+ स्तरों के माध्यम से पास करना गलत आर्किटेक्चर का संकेत है; घटक पदानुक्रम पर पुनर्विचार करें।
State Hoisting पुनर्संयोजन की संख्या को थोड़ा बढ़ा सकता है क्योंकि पैरेंट में परिवर्तन सभी चाइल्ड को पुनर्संयोजित कर सकता है। परिवर्तनों को फ़िल्टर करने के लिए derivedStateOf और लक्षित अपडेट के लिए LazyColumn में keys का उपयोग करें। अधिकांश परिदृश्यों में, State Hoisting का ओवरहेड रखरखाव क्षमता के लाभ की तुलना में नगण्य है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें