Update README.md
This commit is contained in:
368
README.md
368
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 است.**
|
||||||
|
|||||||
Reference in New Issue
Block a user