۱۰ اشتباه کامپوز در موقع کار با Compose و چطور ازشون جلوگیری کنیم


در این مقاله به 10 اشتباه کامپوز که حتی برنامه نویس های با تجربه هم ممکنه مرتکب بشن ، را بررسی میکنیم . . .
Jetpack Compose واقعاً نحوهی ساخت رابط کاربری (UI) تو اپهای اندرویدی رو دگرگون کرده. چون با روش جدیدی به اسم Declarative UI کار میکنه که کلی از دردسرای قدیمی رو حذف کرده. ولی خب، در عوض یهسری مفاهیم جدید هم وارد کرده که حتی برنامهنویسهای با تجربه هم ممکنه گول بخورن و اشتباه کنن.
تو این مطلب، میخوایم به ۱۰ تا از اشتباههای رایج موقع کار با Jetpack Compose نگاه کنیم و برای هر کدوم توضیح و نمونه کد بزنیم تا بهتر بتونید ازشون دوری کنید.
۱. فراموش کردن استفاده درست از remember – مهم ترین و بیشترین اشتباه کامپوز
تو Jetpack Compose مدیریت state خیلی مهمه. یکی از ابزارهای اصلی برای این کار تابع remember هست. اگه موقع تعریف متغیری که باید بین بازسازیهای (recomposition) مختلف حفظ بشه از remember استفاده نکنید، اون مقدار هربار ریست میشه و میتونه باگ و مشکل عملکردی ایجاد کنه.
❌ اشتباه:
var count by mutableStateOf(0)
Button(onClick = { count++ }) {
Text("Count: $count")
}
✅ درستش:
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Count: $count")
}
اینجا remember کمک میکنه که مقدار count توی بازسازیهای مجدد حفظ بشه.
۲. استفادهی بیش از حد از Modifier.fillMaxSize()
خیلی وقتا برای پر کردن کل فضا از fillMaxSize() استفاده میکنیم. ولی اگه این کار رو بیحسابوکتاب انجام بدیم، رابط کاربری بهمریخته و بینظمی خواهیم داشت.
❌ اشتباه:
Column(modifier = Modifier.fillMaxSize()) {
Text("Title")
Button(onClick = {}) {
Text("Click me")
}
}
✅ درستش:
Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
Text("Title")
Spacer(modifier = Modifier.height(8.dp))
Button(
onClick = {},
modifier = Modifier.align(Alignment.CenterHorizontally)
) {
Text("Click me")
}
}
با استفاده از fillMaxWidth() و کمی padding چیدمان خیلی مرتبتر میشه.
۳. بیتوجهی به بهینهسازی عملکرد (Performance)
Jetpack Compose به سبک Declarative نوشته میشه، ولی اگه بهینهسازی رو فراموش کنیم، باعث افت عملکرد میشه. استفاده درست از remember، مدیریت state و جلوگیری از بازسازیهای غیرضروری خیلی مهمه.
❌ اشتباه:
@Composable
fun MyComposable() {
val name = getNameFromDatabase() // عملیات سنگین
Text("Hello, $name")
}
✅ درستش:
@Composable
fun MyComposable() {
val name by remember { mutableStateOf(getNameFromDatabase()) }
Text("Hello, $name")
}
مراجعه برای مطالعه بیشتر در مورد بهینه سازی در کامپوز داده : بهینه سازی در کامپوز
۴. قاطی کردن State و MutableState
خیلیها مخصوصاً تازهکارها این دو تا رو با هم قاطی میکنن. State فقط قابل خواندنه ولی MutableState قابل تغییر دادن هست و میتونه باعث بازسازی مجدد UI بشه.
❌ اشتباه:
val name: State<String> = remember { mutableStateOf("John") }
name.value = "Doe" // ارور: State فقط خواندنیه
✅ درستش:
var name by remember { mutableStateOf("John") }
name = "Doe" // مقدار جدید رو بهش میدیم
۵. استفادهی اشتباه از LaunchedEffect
LaunchedEffect برای اجرای عملیاتهایی مثل درخواست شبکه یا انیمیشن که خارج از چرخه معمولی هستن، استفاده میشه. ولی اگه درست ازش استفاده نکنید ممکنه نتایج عجیبی بگیرید یا اثر ناخواسته ایجاد بشه.
LaunchedEffect چیه؟
یه تابع کامپوزابله که یه coroutine راهاندازی میکنه و به یه کلید (key) خاص وابستهست. تا وقتی اون کلید تغییر نکنه یا کامپوز از صفحه حذف نشه، coroutine اجرا میمونه. برای کارهایی مثل درخواست شبکه یا شروع انیمیشن خیلی کاربردیه.
اشتباههای رایج و راهحلشون
❌ اشتباه ۱: ندادن کلید مناسب
🔴 مشکل: فقط یکبار اجرا میشه، حتی اگه userId عوض بشه.
✅ درستش:
LaunchedEffect(userId) {
val userData = fetchUserData(userId)
}
❌ اشتباه ۲: استفاده از کلیدهای بیربط که زیاد تغییر میکنن
LaunchedEffect(userName) {
val userData = fetchUserData(userId)
}
🔴 مشکل: ممکنه بیدلیل چند بار اجرا بشه.
✅ درستش:
LaunchedEffect(userId) {
val userData = fetchUserData(userId)
}
❌ اشتباه ۳: نفهمیدن چرخه عمر LaunchedEffect
if (isVisible) {
LaunchedEffect(userId) {
val userData = fetchUserData(userId)
}
}
🔴 مشکل: وقتی isVisible = false بشه، اثر قطع میشه و دوباره اجرا شدنش ممکنه بیدلیل باشه.
✅ بهتره به رفتار lifecycle آگاه باشید. اگه نیاز به cleanup دارید از DisposableEffect استفاده کنید.
نکات مهم برای استفاده از LaunchedEffect
- از کلید مناسب استفاده کنید (نه خیلی عمومی، نه خیلی خاص)
- از انجام کارهای سنگین تو هر بازسازی پرهیز کنید
- چرخه عمرش رو بدونید و اگه نیاز به تمیزکاری داشتید از DisposableEffect کمک بگیرید
۶. مدیریت بد بازسازی (Recomposition)
هر بار که state عوض میشه، کامپوز بازسازی میشه. اگه حواسمون نباشه ممکنه کارایی پایین بیاد. و اشتباه کامپوز که بسیار دردسر ساز میشه .
❌ اشتباه:
@Composable
fun MyComposable() {
val list = (1..100).toList()
list.forEach {
Text("Item: $it")
}
}
✅ درستش:
@Composable
fun MyComposable() {
val list = (1..100).toList()
LazyColumn {
items(list) { item ->
Text("Item: $item")
}
}
}
۷. شلوغ کردن UI با کامپوزابلهای تو در تو
کامپوزابلهای زیاد تو در تو، خوندن و نگهداری کد رو سخت میکنه. « اشتباه کامپوز که موجب این گفتمان میشه : اخه این چیه نوشتی ! »
❌ اشتباه:
Column {
Row {
Text("Name:")
Text("John Doe")
}
Row {
Text("Age:")
Text("30")
}
}
✅ درستش:
@Composable
fun UserInfo(label: String, info: String) {
Row {
Text("$label: ")
Text(info)
}
}
@Composable
fun ComplexUI() {
Column {
UserInfo(label = "Name", info = "John Doe")
UserInfo(label = "Age", info = "30")
// Reuse UserInfo composable for other rows...
}
}
۸. بیتوجهی به تم و استایل
استفاده از MaterialTheme باعث میشه ظاهر اپ یکدست و حرفهای باشه.
❌ اشتباه:
Text("Hello", color = Color.Blue, fontSize = 18.sp)
✅ درستش:
@Composable
fun MyComposable() {
Text(
"Hello, World!",
style = MaterialTheme.typography.h6,
color = MaterialTheme.colors.primary
)
}
۹. بیتوجهی به تستنویسی
تست نوشتن باعث میشه مطمئن بشیم UI تو شرایط مختلف درست کار میکنه. میشه گفت یکی از مخفی ترین اشتباه کامپوز عه اما تاثیر زیادی داره .
❌ اشتباه: هیچ تستی نوشته نشده
✅ درستش:
۱۰. نادیده گرفتن دسترسپذیری (Accessibility)
وقتی یه اپلیکیشن میسازیم، باید کاری کنیم که همهی افراد بتونن از اون استفاده کنن — حتی کسانی که مشکلات بینایی، شنوایی یا حرکتی دارن. این یعنی اپلیکیشن ما باید با ابزارهای کمکی مثل Screen Reader (که متن رو با صدا میخونه) سازگار باشه.
Jetpack Compose ابزارهایی مثل contentDescription و semantics داره که کمک میکنن اپلیکیشن برای این گروه از کاربران هم قابل استفاده باشه ، اگه این مورد رو حل کنیم ، این اشتباه کامپوز به یه حرکت با کلاس تبدیل میشه
❌ اشتباه:
@Composable
fun ImageWithoutDescription() {
Image(painter = painterResource(id = R.drawable.my_image), contentDescription = null)
}
✅ درستش:
@Composable
fun AccessibleImage() {
Image(
painter = painterResource(id = R.drawable.my_image),
contentDescription = "Description of the image"
)
}
جمعبندی
Jetpack Compose یه ابزار قدرتمند برای سادهتر کردن توسعه رابط کاربری توی اندرویده، ولی چالشهای خودش رو هم داره.
اگه از اشتباه کامپوز رایجی که گفتیم آگاه باشی و بتونی ازشون دوری کنی، میتونی اپلیکیشنهایی بسازی که هم بهتر کار میکنن، هم راحتتر قابل نگهداری هستن، و هم برای همهی کاربرا قابل استفادهان.
یادت باشه هدف فقط این نیست که کدت کار کنه، بلکه باید قوی، تمیز و قابل توسعه هم باشه.
برنامهنویسیتون پر انرژی! 😊







