SideEffect Jetpack Compose में एक composable फ़ंक्शन है जो प्रत्येक सफल पुनरसंरचना पर पास्कित कोड ब्लॉक को निष्पादित करता है। LaunchedEffect और DisposableEffect के विपरीत, SideEffect कुंजीओं से बंधा नहीं है और इसमें कोई साफ़-सफाई ब्लॉक नहीं है — यह बस प्रत्येक रेंडरिंग के बाद Compose अवस्था को बाहरी सिस्टम से सिंक्रोनाइज़ करता है। यह इसे कॉलबैक फ़ंक्शनों को अपडेट करने, ViewPager के साथ सिंक्रोनाइज़ करने और Analytics SDK में डेटा भेजने के लिए आदर्श बनाता है। Android Developers Documentation (2025) के अनुसार, SideEffect कोम्पोज़ द्वारा सफल पुनरसंरचना की पुष्टि के बाद ही निष्पादित होता है, और यदि पुनरसंरचना छोड़ दी जाती है तो निष्पादित नहीं होता है।
मुख्य बातें
SideEffect Jetpack Compose में सबसे सरल साइड-इफेक्ट API है। यह एक composable घटक की प्रत्येक सफल पुनरसंरचना पर एक कोड ब्लॉक निष्पादित करता है। यहाँ “सफल” शब्द महत्वपूर्ण है: यदि Compose तय करता है कि पुनरसंरचना आवश्यक नहीं है (उदाहरण के लिए, सभी इनपुट पैरामीटर अपरिवर्तित हैं और परिणाम वही होगा), तो SideEffect निष्पादित नहीं होता है। यह सुनिश्चित करता है कि सिंक्रोनिजेशन ब्लॉक को केवल तब बुलाया जाए जब UI वास्तव में बदल गया हो।
SideEffect का मुख्य उपयोग Compose अवस्था को उन वस्तुओं के साथ सिंक्रोनाइज़ करना है जो Compose ट्री का हिस्सा नहीं हैं। विशिष्ट उदाहरणों में शामिल हैं: Legacy View सिस्टम में कॉलबैक फ़ंक्शन अपडेट करना, ViewPager में वर्तमान अवस्था भेजना, प्रदर्शित डेटा बदलने पर Analytics SDK में एक इवेंट भेजना, और मैपिंग SDK के साथ सिंक्रोनाइज़ करना जो एक बाहरी प्रारूप में अपडेट की उम्मीद करते हैं।
Android Developer Blog (2025) के अनुसार, SideEffect अक्सर remember के साथ संयोजन में उपयोग किया जाता है: remember एक वस्तु (जैसे कि कॉलबैक) को संग्रहित करता है, और SideEffect इसे जब भी कोई निर्भरता बदलती है अपडेट करता है। यह पैटर्न विशेष रूप से उन लाइब्रेरी के लिए महत्वपूर्ण है जो लिसनर ऑब्जेक्ट स्वीकार करते हैं और अपडेट पर उन्हें पुनर्नवीमाणित नहीं करते — SideEffect के बिना, लिसनर में वर्तमान अवस्था का पुराना संदर्भ होगा।
@Composable
fun MapScreen(zoomLevel: Int, markers: List<Marker>) {
val mapView = remember { MapView(LocalContext.current) }
SideEffect {
mapView.setZoom(zoomLevel)
mapView.updateMarkers(markers)
}
AndroidView(factory = { mapView })
}
SideEffect को समझने के लिए, आपको Jetpack Compose के निष्पादन चरणों को समझना होगा। Compose प्रत्येक फ्रेम के लिए तीन चरणों से गुजरता है: Composition (क्या दिखाना है), Layout (कहाँ दिखाना है), Drawing (कैसे दिखाना है)। SideEffect Composition चरण के अंत में निष्पादित होता है — सभी composable फ़ंक्शनों के चलने के बाद, लेकिन Layout चरण से पहले। यह सुनिश्चित करता है कि SideEffect पुनरसंरचना के बाद सभी चर की अंतिम स्थिति देखता है।
जीवन चक्र में यह स्थान एक महत्वपूर्ण लाभ देता है: SideEffect अनंत पुनरसंरचना का कारण नहीं बन सकता, भले ही इसके भीतर अवस्था बदल दी जाए। क्योंकि यह कंपोज़ीशन के बाद निष्पादित होता है, SideEffect के भीतर किए गए बदलाव केवल अगले फ्रेम में लागू होंगे — यह एक composable फ़ंक्शन के भीतर अवस्था परिवर्तनों के विशिष्ट चक्रों को रोकता है (जब कंपोज़ीशन के भीतर setState वर्तमान कंपोज़ीशन के समाप्त होने से पहले एक नयी कंपोज़ीशन को ट्रिगर करता है)।
एक और विशेषता यह है कि SideEffect कुंजीओं द्वारा ऑप्टिमाइज़ नहीं किया जाता है। यह प्रत्येक पुनरसंरचना पर निष्पादित होता है चाहे कोई भी विशिष्ट अवस्था बदली हो। यदि आपको अधिक सटीक नियंत्रण चाहिए (केवल तब निष्पादित करें जब कोई विशिष्ट पैरामीटर बदलता है), तो कुंजी के सاथ LaunchedEffect का उपयोग करें या SideEffect को remember के माध्यम से परिवर्तन जांच में लपेटें।
// रिमेंबर के साथ ऑप्टिमाइज़ SideEffect
var currentZoom by remember { mutableIntStateOf(zoomLevel) }
SideEffect {
if (currentZoom != zoomLevel) {
map.animateToZoom(zoomLevel)
currentZoom = zoomLevel
}
}
// इस जाँच के बिना SideEffect animateToZoom को कॉल करेगा
// भले ही zoomLevel न बदला हो, हर पुनरसंरचना पर
SideEffect के लिए सबसे आम व्यावहारिक परिदृश्य वर्तमान अवस्था को कॉप्चर करने वाले कॉलबैक फ़ंक्शनों को अपडेट करना है। Jetpack Compose में इसे “callback lifecycle management” कहा जाता है। समस्या यह है कि Kotlin में lambda अभिव्यक्तियाँ चर को संदर्भ द्वारा कॉप्चर करती हैं, और यदि एक कॉलबैक एक मान के साथ बनाया गया था और बाद में चर बदल गया — तो कॉलबैक पुराने मान का उपयोग करता रहता है।
एक उदाहरण पर विचार करें: Android के लिए Google Maps SDK setOnCameraMoveListener() के माध्यम से एक OnCameraMoveListener ऑब्जेक्ट स्वीकार करता है। यदि आप एक lambda पास करते हैं जो isTrackingEnabled को कॉप्चर करती है, तो जब isTrackingEnabled बदलता है तो lambda अपडेट नहीं होगी — Maps SDK पुराने डेटा के साथ पुराने कॉलबैक को कॉल करता रहेगा। SideEffect इस समस्या को हल करता है: यह प्रत्येक पुनरसंरचना पर लिसनर को पुनर्निर्धारित करता है, जिससे यह सुनिश्चित होता है कि SDK हमेशा नवीनतम अवस्था के साथ वर्तमान lambda का उपयोग करता है।
Maps SDK for Android Documentation (2025) के अनुसार, Google Maps को Jetpack Compose के साथ एकीकृत करते समय ठीक इसी पैटर्न की अनुशंसा करता है। एक समान दृष्टिकोण WebView, VideoView, TextureView और किसी भी अन्य View-आधारित घटकों के लिए उपयोग किया जाता है जो set-विधियों के माध्यम से callbacks स्वीकार करते हैं। SideEffect यह सुनिश्चित करता है कि प्रत्येक अवस्था परिवर्तन के साथ callbacks अपडेट होते रहें।
@Composable
fun MapComposable(isTrackingEnabled: Boolean, onMarkerClick: (Marker) -> Unit) {
val mapView = remember { MapView(LocalContext.current) }
SideEffect {
mapView.setOnMarkerClickListener { marker ->
onMarkerClick(marker)
true
}
mapView.isTrafficEnabled = isTrackingEnabled
}
AndroidView(factory = { mapView })
}
SideEffect के लिए एक और महत्वपूर्ण परिदृश्य UI अवस्था बदलने पर विश्लेषण प्रणालियों में इवेंट भेजना है। उदाहरण के लिए, जब कोई उपभोक्ता Compose स्क्रीन के भीतर TabLayout में टैब बदलता है, तो SideEffect वर्तमान चयनित टैब स्थिति को Firebase Analytics या AppsFlyer में भेज सकता है। हर बार जब चयनित टैब बदलती है (और पुनरसंरचना होती है), SideEffect संबंधित इवेंट भेजता है।
onClick या onTabSelected में सीधे इवेंट भेजने से अंतर यह है कि SideEffect किसी भी स्रोत से अवस्था परिवर्तनों पर ट्रिगर होता है — न केवल उपभोक्ता क्रियाएँ, बल्कि प्रोग्रामेटिक परिवर्तन, स्क्रीन रोटेशन के बाद अवस्था बहाली, या Deep Links भी। यह SideEffect को परिवर्तन स्रोत से स्वतंत्र एक सार्वभौमिक सिंक्रोनिजेशन तंत्र बनाता है।
Firebase Best Practices (Google, 2025) के अनुसार, SideEffect के माध्यम से विश्लेषण इवेंट भेजने से उपभोक्ता यात्रा की अधिक संपूर्ण तस्वीर मिलती है, क्योंकि यह अवस्था के सभी परिवर्तनों को कैप्चर करता है, जिसमें वे भी शामिल हैं जो प्रत्यक्ष उपभोक्ता क्रिया के बिना होते हैं। हालाँकि इसे जरूरत से अधिक नहीं करना चाहिए: प्रत्येक विश्लेषण इवेंट एक नेटवर्क अनुरोध है, इसलिए बार-बार बदलने वाली अवस्थाओं (स्क्रॉल स्थिति, उंगली निर्देशांक) के लिए SideEffect उपयुक्त नहीं है — debounce का उपयोग करें या केवल महत्वपूर्ण परिवर्तनों पर ही इवेंट भेजें।
@Composable
fun ProductScreen(selectedTab: ProductTab, productId: String) {
val firebaseAnalytics = remember { FirebaseAnalytics.getInstance(LocalContext.current) }
SideEffect {
val params = Bundle().apply {
putString(FirebaseAnalytics.Param.CONTENT_TYPE, selectedTab.name)
putString(FirebaseAnalytics.Param.ITEM_ID, productId)
}
firebaseAnalytics.logEvent( FirebaseAnalytics.Event.VIEW_ITEM, params)
}
// TabRow और चयनित टैब के सاथ UI
}
SideEffect और LaunchedEffect के बीच चुनाव दो कारकों पर निर्भर करता है: क्या असिंक्रोनस निष्पादन आवश्यक है और क्या कुंजी-आधारित नियंत्रण आवश्यक है। SideEffect सिंक्रोनस है और प्रत्येक पुनरसंरचना पर निष्पादित होता है। LaunchedEffect असिंक्रोनस (कोरूटिन) है और केवल तब निष्पादित होता है जब कुंजी बदलती है, प्रत्येक पुनरसंरचना पर नहीं।
| विशेषता | SideEffect | LaunchedEffect |
|---|---|---|
| निष्पादन | प्रत्येक पुनरसंरचना पर | कुंजी बदलने पर |
| असिंक्रोनिजेशन | सिंक्रोनस | कोरूटिन |
| कुंजी | नहीं | हाँ (vararg) |
| साफ़-सफाई | नहीं | स्वचालित कोरूटिन रद्दीकरण |
| विशिष्ट उपयोग | Callbacks, Analytics, दृश्य सिंक्रोनिजेशन | लोडिंग, Flow सदस्यता, टाइमर |
व्यावहारिक रूप से, साइड इफेक्ट के 70% मामलों में LaunchedEffect (असिंक्रोनस संचालन, डेटा लोडिंग), 20% में DisposableEffect (साफ़-सफाई के साथ संसाधन) और केवल 10% में SideEffect (callback सिंक्रोनिजेशन) का उपयोग होता है। SideEffect कार्यों के एक सीमित दायरे के लिए एक विशेषिज़ उपकरण है, लेकिन उन कार्यों में यह अपरिहार्य है।
मुख्य गलती है SideEffect के भीतर Compose अवस्था को बदलना। हालाँकि SideEffect सीधे अनंत लूप का कारण नहीं बनता (क्योंकि यह कंपोज़ीशन चरण के बाद निष्पादित होता है), यह अतिरिक्त पुनरसंरचनाओं को ट्रिगर कर सकता है। यदि SideEffect के भीतर अवस्था बदली जाती है (mutableStateOf), तो यह अगले फ्रेम में एक नयी पुनरसंरचना को ट्रिगर करती है, जो फिर SideEffect को निष्पादित करती है — और यह सिल्सिला स्थिरीकरण तक जारी रहता है। यह अनंत लूप नहीं है, लेकिन फ्रेमवर्क के लिए अनावश्यक कार्य है।
दूसरी गलती है SideEffect के भीतर भारी गणनाएँ करना। चूँकि SideEffect प्रत्येक पुनरसंरचना पर बुलाया जाता है, और पुनरसंरचनाएँ दर्जनों बार प्रति सेकंड हो सकती हैं (एनिमेशन, स्क्रॉलिंग के दौरान), SideEffect के भीतर कोई भी भारी कोड फ्रेम ड्रॉप का कारण बनेगा। भारी संचालनों को कंपोज़ीशन से बाहर ले जाएँ — एक कोरूटिन (LaunchedEffect) में या derivedStateOf / remember के माध्यम से गणना करें।
तीसरी गलती है SideEffect का असिंक्रोनस कोड के लिए उपयोग करना। SideEffect एक suspend फ़ंक्शन नहीं है, इसलिए delay(), await(), collect() और अन्य कोरूटिन संचालन इसके भीतर कंपाइल नहीं होंगे। यदि आपको पुनरसंरचना के बाद एक असिंक्रोनस कार्रवाई करने की आवश्यकता है, तो LaunchedEffect के साथ snapshotFlow { ... } का उपयोग करें, या rememberCoroutineScope के माध्यम से एक कोरूटिन शुरू करें।
अक्सर पूछे जाने वाले प्रश्न
हाँ, SideEffect प्रत्येक सफल कंपोज़ीशन पर निष्पादित होता है, जिसमें पहली भी शामिल है — जब घटक पहली बार स्क्रीन पर दिखाई देता है। यह इसे LaunchedEffect(Unit) से अलग करता है, जो पहली कंपोज़ीशन पर एक बार निष्पादित होता है लेकिन बाद की पुनरसंरचनाओं पर नहीं (यदि कुंजी नहीं बदली है)।
नहीं, SideEffect कंपोज़ीशन चरण के बाद निष्पादित होता है — इसके भीतर किए गए बदलाव केवल अगले फ्रेम में लागू होंगे, जो लूप को रोकता है। हालाँकि SideEffect के भीतर बार-बार अवस्था बदलने से पुनरसंरचनाओं का हिमपात हो सकता है, जिससे प्रदर्शन कम हो सकता है। SideEffect के भीतर अवस्था केवल तब बदलें जब वास्तव में आवश्यक हो।
SideEffect प्रत्येक पुनरसंरचना पर सिंक्रोनस रूप से निष्पादित होता है। snapshotFlow Compose अवस्था से एक Flow बनाता है और प्रतिक्रियात्मक परिवर्तन हैंडलिंग के लिए LaunchedEffect में collectLatest के साथ उपयोग किया जा सकता है। snapshotFlow उन मामलों के लिए उपयुक्त है जहाँ आपको debounce, filter या distinctUntilChanged के साथ परिवर्तनों पर प्रतिक्रिया करने की आवश्यकता है — जो सिंक्रोनस SideEffect में असंभव है।
Android Studio Compose Modifier Debugger का उपयोग करें या घटक नाम और कॉल आवृत्ति के साथ लॉगिंग जोड़ें। यदि SideEffect उम्मीद से अधिक बार निष्पादित हो रहा है, तो जाँचें कि क्या मूल घटक की अवस्था अनावश्यक रूप से बदल रही है। ऑप्टिमाइजेशन: UI के स्थिर भागों को unstable एनोटेशन के साथ अलग composable फ़ंक्शनों में निकालें ताकि पुनरसंरचनाओं की संख्या कम हो।
हाँ, उन्हें अलग-अलग उद्देश्यों के लिए एक ही घटक में उपयोग किया जा सकता है। DisposableEffect एक संसाधन को सेट अप और साफ़ करने (एक बार) के लिए जिम्मेदार है, जबकि SideEffect प्रत्येक पुनरसंरचना पर उस संसाधन के साथ वर्तमान अवस्था को सिंक्रोनाइज़ करने का ध्यान रखता है। एक विशिष्ट उदाहरण: DisposableEffect एक API के माध्यम से एक callback पंजीकृत करता है, और SideEffect प्रत्येक परिवर्तन पर उस callback में कॉप्चर किए गए डेटा को अपडेट करता है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें