diff --git a/README.md b/README.md index 9125713..9989434 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,368 @@ -# 06-compose-state +# 1. مشکل از کجا شروع شد؟ + +قبل از Jetpack Compose در اندروید، وقتی داده‌ای در برنامه تغییر می‌کرد باید **خودمان دستی UI را آپدیت می‌کردیم**. + +مثال: + +کاربر روی دکمه افزایش کلیک می‌کند → مقدار عدد تغییر می‌کند → باید TextView را هم تغییر دهیم. + +در View های قدیمی: + +```kotlin +count++ +textView.text = count.toString() +``` + +یعنی برنامه‌نویس **باید یادش بماند UI را هم آپدیت کند**. + +مشکل‌ها: + +- ممکن است فراموش کنیم UI را آپدیت کنیم +- کدها پیچیده می‌شوند +- نگهداری سخت می‌شود + +--- + +# 2. راه‌حل Compose چیست؟ + +در Compose یک قانون مهم داریم: + +**UI باید تابعی از State باشد** + +یعنی: + +``` +UI = f(state) +``` + +اگر state تغییر کند → UI خودش دوباره ساخته می‌شود. + +به این فرایند می‌گوییم: + +**Recomposition** + +--- + +# 3. State چیست؟ + +State یعنی: + +**داده‌ای که اگر تغییر کند، UI باید تغییر کند.** + +مثال‌ها: + +- مقدار counter +- متن داخل TextField +- وضعیت لودینگ +- لیست پیام‌ها +- وضعیت لاگین کاربر + +مثال ساده: + +```kotlin +var count = 0 +``` + +اگر مقدار `count` تغییر کند، UI باید تغییر کند. + +اما Compose از تغییر این متغیر خبر ندارد. + +پس باید از **State مخصوص Compose** استفاده کنیم. + +--- + +# 4. mutableStateOf چیست؟ + +برای اینکه Compose بفهمد داده تغییر کرده باید از **State Object** استفاده کنیم. + +یکی از مهم‌ترین آن‌ها: + +``` +mutableStateOf +``` + +مثال: + +```kotlin +var count = mutableStateOf(0) +``` + +اینجا count یک **State** است. + +برای دسترسی به مقدار: + +``` +count.value +``` + +مثال: + +```kotlin +count.value++ +``` + +وقتی مقدار تغییر کند: + +Compose متوجه می‌شود → UI دوباره ساخته می‌شود. + +--- + +# 5. استفاده از State در Compose + +یک مثال ساده Counter: + +```kotlin +@Composable +fun CounterScreen() { + + var count = remember { mutableStateOf(0) } + + Column { + + Text(text = "Count: ${count.value}") + + Button(onClick = { + count.value++ + }) { + Text("Increase") + } + + } +} +``` + +اتفاقی که می‌افتد: + +1️⃣ صفحه ساخته می‌شود +2️⃣ مقدار count = 0 +3️⃣ Text مقدار 0 را نشان می‌دهد +4️⃣ کاربر دکمه را می‌زند +5️⃣ مقدار count تغییر می‌کند +6️⃣ Compose تشخیص می‌دهد state تغییر کرده +7️⃣ UI دوباره اجرا می‌شود + +این فرایند همان **Recomposition** است. + +--- + +# 6. Recomposition چیست؟ + +**Recomposition یعنی اجرای دوباره Composable ها وقتی State تغییر می‌کند.** + +در مثال قبل: + +وقتی: + +``` +count.value++ +``` + +اجرا می‌شود + +Compose: + +- متوجه تغییر state می‌شود +- Composable مربوطه را دوباره اجرا می‌کند +- UI جدید رسم می‌شود + +نکته مهم: + +Compose **کل صفحه را دوباره نمی‌سازد** +فقط بخش‌هایی که نیاز دارند دوباره اجرا می‌شوند. + +--- + +# 7. remember چیست؟ + +یک مشکل مهم وجود دارد. + +اگر این کد را بنویسیم: + +```kotlin +var count = mutableStateOf(0) +``` + +در هر Recomposition مقدار دوباره **0 می‌شود**. + +چرا؟ + +چون تابع دوباره اجرا می‌شود. + +برای حل این مشکل از: + +``` +remember +``` + +استفاده می‌کنیم. + +```kotlin +var count = remember { mutableStateOf(0) } +``` + +remember باعث می‌شود: + +✅ مقدار بین recomposition ها حفظ شود. + +--- + +# 8. روش بهتر: by delegation + +نوشتن `.value` کمی آزاردهنده است. + +روش بهتر: + +```kotlin +var count by remember { mutableStateOf(0) } +``` + +حالا می‌توانیم مستقیم استفاده کنیم: + +```kotlin +count++ +``` + +مثال کامل: + +```kotlin +@Composable +fun CounterScreen() { + + var count by remember { mutableStateOf(0) } + + Column { + + Text(text = "Count: $count") + + Button(onClick = { + count++ + }) { + Text("Increase") + } + + } +} +``` + +--- + +# 9. جریان کامل اتفاقات + +مراحل اجرای برنامه: + +1️⃣ Composable اجرا می‌شود +2️⃣ State ساخته می‌شود +3️⃣ UI بر اساس State ساخته می‌شود + +وقتی کاربر دکمه را می‌زند: + +4️⃣ State تغییر می‌کند +5️⃣ Compose تغییر را تشخیص می‌دهد +6️⃣ Recomposition انجام می‌شود +7️⃣ UI جدید ساخته می‌شود + +--- + +# 10. مثال Counter کامل + +```kotlin +@Composable +fun CounterScreen() { + + var count by remember { mutableStateOf(0) } + + Column { + + Text( + text = "Count: $count", + fontSize = 30.sp + ) + + Button( + onClick = { count++ } + ) { + Text("Increase") + } + + Button( + onClick = { count-- } + ) { + Text("Decrease") + } + + } +} +``` + +--- + +# 11. نکات مهم + +✅ State داده‌ای است که UI به آن وابسته است. + +✅ وقتی State تغییر کند → Recomposition اتفاق می‌افتد. + +✅ برای تعریف State از `mutableStateOf` استفاده می‌کنیم. + +✅ برای حفظ مقدار در Recomposition از `remember` استفاده می‌کنیم. + +✅ بهتر است از `by` استفاده کنیم تا `.value` حذف شود. + +--- + +# 12. تمرین برای دانشجویان + +1️⃣ یک Counter بسازید که دکمه‌های زیر داشته باشد: + +- Increase +- Decrease +- Reset + +2️⃣ اگر مقدار Counter به **10 رسید** یک متن نمایش دهید: + +``` +Maximum reached! +``` + +3️⃣ اگر مقدار Counter **منفی شد** رنگ متن قرمز شود. + +--- + +# 13. چالش فکری + +اگر به جای State این کد را بنویسیم: + +```kotlin +var count = 0 +``` + +و در Button مقدار را زیاد کنیم: + +``` +count++ +``` + +آیا UI تغییر می‌کند؟ + +چرا؟ + +--- + +پاسخ: +خیر. چون Compose از تغییر این متغیر خبر ندارد. بنابراین Recomposition اتفاق نمی‌افتد. + +--- + +# جمع‌بندی + +مهم‌ترین مفاهیم Compose: + +- State → داده قابل تغییر UI +- mutableStateOf → ساخت state +- remember → نگهداری مقدار در recomposition +- Recomposition → اجرای دوباره UI بعد از تغییر state + +قانون اصلی Compose: + +**UI تابعی از State است.**