مفهوم State در کامپوز Jetpack Compose


در این مقاله به صورت خیلی ساده و روان به مفهوم State در Compose میپردازیم .
تعریف State
در Jetpack Compose، منظور از State (وضعیت) دادههایی هستند که رابط کاربری (UI) را تحت تأثیر قرار میدهند. زمانی که State تغییر کند، رابط کاربری نیز بازترکیب (Recompose) میشود.
مدیریت مؤثر State یکی از اصول کلیدی برای ساخت رابطهای کاربری پویا، پاسخگو و قابل نگهداری است.
State میتواند داده های مختلفی باشد:
- یک مقدار محلی داخل کلاس یا تابع
- یک داده در دیتابیس
- اطلاعات دریافتی از حسگرها
- دادههایی که در ViewModel نگهداری میشوند
تفاوت Stateless و Stateful
Stateless
تابع کامپوزی که هیچ state داخلی ندارد و دادهها و رفتارهایش از بیرون به آن منتقل میشود. این نوع توابع سادهتر، قابلتستتر و قابل استفاده مجدد هستند. برای مدیریت تغییرات State در این حالت از State Hoisting استفاده میکنیم.که در ادامه به این مفهوم اشاره میکنم .
Stateful
تابعی که خودش یک state داخلی دارد (مثلاً با remember { mutableStateOf(…) }) و به طور مستقیم آن را کنترل میکند. این حالت در مواقعی که تابع نیاز دارد خودش به تغییرات پاسخ دهد کاربرد دارد، ولی نگهداری و تست آن سختتر است.
مفهوم Recomposition
وقتی که مقدار یک State تغییر میکند، Compose رابط کاربری را دوباره رسم میکند. به این فرآیند Recomposition گفته میشود.
تا زمانی که state تغییر نکند، تابع composable نیز تغییر نخواهد کرد.
نقش remember و mutableStateOf
- remember وظیفه دارد که مقدار را فقط در طول یک کامپوزیشن ذخیره کند و در Recompositionهای بعدی همان مقدار را بازگرداند.
- mutableStateOf وظیفه نگهداری مقدار قابل تغییر را دارد که در صورت تغییر، باعث Recompose شدن UI میشود.
سؤال رایج:
آیا remember باعث State شدن یک مقدار میشود؟
خیر. mutableStateOf یک State تولید میکند. remember فقط مقدار را در طول یک Composition نگه میدارد.
State Hoisting
الگوی طراحیای است که در آن State از تابع پایینتر به تابع بالاتر منتقل میشود. این کار با استفاده از پارامترها و لامبدا فانکشنها انجام میشود.
همان طور که در شکل بالا مشاهده میکنید ، در کد سمت چپ ، ()ScreenContent شما یه تابع Stateful مشاهده میکنید که حاوی State است و شکل سمت راست ما از الگوی State hoisting استفاده کردیم ، ()ScreenContetn هیچ state ندارد و از تابع بالایی HomeScreen آن را دریافت میکند ،در اینجا تابع HomeScreen وضعیت state را مدیریت میکند و ScreenContent فقط نمایشدهنده است.
ViewModel و نگهداری State
در Compose توصیه میشود از ViewModel برای نگهداری stateهای سطح بالا استفاده شود. یعنی در مثال ما ،که دوتا تابع داشتیم ، اما در پروژه های واقعی ViewModel میتواند از ابزارهایی مانند LiveData یا StateFlow استفاده کند تا تغییرات داده را به UI اعلام کند.
مزایای ViewModel:
- ماندگاری داده در زمان چرخش صفحه
- جداسازی منطق از UI
- قابل استفاده مجدد در چند کامپوز مختلف
بعد از این که این داده های رو در این جا تعریف کردیم استفاده کردن آن ها در UI ما به این شکل خواهد بود
در استفاده کردن از ویومدل به عنوان نگهدارنده State این مفاهیم باید تعریف کنیم :
observeAsState
یک تابع کمکی در Jetpack Compose است که برای اتصال LiveDataیا Flow(یا دیگر منابع دادهای قابل مشاهده) به UI کامپوز استفاده میشود. این تابع دادهی LiveData را به یک State قابل مشاهده توسط Compose تبدیل میکند.
یعنی:
-
کامپوز میتونه تغییرات اون داده رو به صورت خودکار متوجه بشه.
-
هر بار که مقدار LiveData تغییر کنه، کامپوز دوباره ترکیب (recompose) میشه و UI بهروزرسانی میشه.
در واقع:
()ObserveAsState یک لایهی واسط ایجاد میکنه که دادهی LiveData یا Flow رو به یک State تبدیل میکنه تا کامپوز بتونه مستقیماً اون رو در UI استفاده کنه.
val name by viewModel.nameLiveData.observeAsState("")
این خط باعث میشود که هر تغییری در LiveData بلافاصله در UI منعکس شود.
جریان داده یکطرفه (Unidirectional Data Flow)
در این الگو، دادهها از بالا به پایین و رویدادها از پایین به بالا منتقل میشوند. این مدل سادهتر، قابلدرکتر و قابل نگهداریتر است. شکلی که برای بیان State Hoisting استفاده کردم دقیقا این مفهوم رو میرسونه در شکل زیر این الگو نمایش داده شده است
نکات تکمیلی و پرسشهای رایج
- آیا همیشه باید از ViewModel برای نگهداری State استفاده کنیم؟
خیر. اگر کامپوننت شما ساده است (مثلاً یک کارت)، میتوانید State را همانجا نگهداری کنید. ولی در این صورت تابع شما Stateful میشود و انعطافپذیری کمتری خواهد داشت. - Event چیست؟
هر رویدادی (مثلاً لمس دکمه) که منجر به تغییر State شود یک Event محسوب میشود. Eventها باید به بخشهایی از برنامه اطلاع دهند که تغییری رخ داده است. - چرا استفاده بیش از حد از تابعهای Stateful خوب نیست؟
زیرا نگهداری، تست و استفاده مجدد از آنها سختتر میشود.
در آخر امیدوارم با یادگیری این نکات بهتر و تمیز تر کد بزنید ، موفق باشید 🍦