← Назад к вопросам

Для чего нужна функция remember в Jetpack Compose?

1.7 Middle🔥 231 комментариев
#UI и вёрстка#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Для чего нужна функция remember в Jetpack Compose?

remember — это функция для сохранения состояния между перерисовками композиции. Без неё данные будут пересчитываться при каждом перерендеринге.

1. Проблема без remember

@Composable
fun Counter() {
    var count = 0  // Пересчитывается при каждой перерисовке!
    
    Button(onClick = { count++ }) {
        Text("Clicked: $count")
    }
    // count всегда = 0, нажатие не сохраняется
}

Проблема: count переинициализируется каждый раз, изменения теряются.

2. Решение: remember

@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }
    
    Button(onClick = { count++ }) {
        Text("Clicked: $count")
    }
    // count сохраняется между перерисовками!
}

remember хранит значение в памяти и восстанавливает его при перерисовке.

3. Как это работает

// remember сохраняет значение
var count by remember { mutableStateOf(0) }

// При первой композиции: mutableStateOf(0) создаётся
// При второй композиции: remember возвращает СОХРАНЁННОЕ значение
// При третьей композиции: опять возвращает сохранённое (не пересчитывает)

4. remember vs mutableState

mutableStateOf создаёт изменяемое состояние:

val state = mutableStateOf(0)
state.value = 1  // Изменяем значение
println(state.value)  // 1

remember сохраняет это состояние между перерисовками:

val state = remember { mutableStateOf(0) }
// state сохраняется, не теряется при перерисовке

5. Практический пример: форма

@Composable
fun LoginForm() {
    var email by remember { mutableStateOf("") }
    var password by remember { mutableStateOf("") }
    var isLoading by remember { mutableStateOf(false) }
    
    Column(modifier = Modifier.padding(16.dp)) {
        TextField(
            value = email,
            onValueChange = { email = it },
            label = { Text("Email") }
        )
        
        TextField(
            value = password,
            onValueChange = { password = it },
            label = { Text("Password") }
        )
        
        Button(
            onClick = {
                isLoading = true
                // Загружаем...
            },
            enabled = !isLoading
        ) {
            Text(if (isLoading) "Loading..." else "Login")
        }
    }
}

6. remember с computeValue

remember вычисляет значение только при изменении dependencies:

val displayText = remember(email) {
    email.reversed()  // Пересчитается только если email изменится
}

Text(displayText)

7. rememberSaveable — сохранение при пересоздании Activity

remember теряется при пересоздании Activity (rotation и т.д.).

Для сохранения используй rememberSaveable:

// ❌ Потеряется при rotation
var count by remember { mutableStateOf(0) }

// ✅ Сохранится
var count by rememberSaveable { mutableStateOf(0) }

8. remember с объектами

// ❌ Неправильно: создаёт новый объект при каждой перерисовке
@Composable
fun UserProfile() {
    val user = User("John")  // Новый объект каждый раз!
    // user != user при следующей перерисовке
}

// ✅ Правильно: сохраняет объект
@Composable
fun UserProfile() {
    val user by remember { mutableStateOf(User("John")) }
    // Тот же объект при перерисовке
}

9. remember с лямбдами (computeValue)

@Composable
fun FilteredList(query: String) {
    val items = listOf("apple", "banana", "apricot")
    
    // Пересчитывается только если query изменится
    val filtered = remember(query) {
        items.filter { it.startsWith(query) }
    }
    
    Text("Found: ${filtered.size}")
}

10. Без remember vs с remember

❌ Без remember:

@Composable
fun BadCounter() {
    var count = 0  // Каждый раз 0
    
    Button(onClick = { count++ }) {  // count не сохраняется
        Text("Count: $count")
    }
}

✅ С remember:

@Composable
fun GoodCounter() {
    var count by remember { mutableStateOf(0) }
    
    Button(onClick = { count++ }) {  // count сохраняется!
        Text("Count: $count")
    }
}

11. Жизненный цикл remember

Первая композиция:
→ remember вычисляет значение
→ сохраняет в памяти
→ возвращает значение

Вторая композиция:
→ remember возвращает СОХРАНЁННОЕ значение (БЕЗ пересчёта)
→ computeValue НЕ вызывается

Удаление композиции:
→ remember освобождает память

12. remember с dependencies (ключи)

@Composable
fun Calculator(a: Int, b: Int) {
    // Пересчитывается только если a или b изменятся
    val sum = remember(a, b) {
        a + b
    }
    
    Text("Sum: $sum")
}

13. Сложный пример: Searchable List

@Composable
fun SearchableList(items: List<String>) {
    var query by remember { mutableStateOf("") }
    
    // Пересчитывается только при изменении query
    val filtered = remember(query, items) {
        items.filter { it.contains(query, ignoreCase = true) }
    }
    
    Column {
        TextField(
            value = query,
            onValueChange = { query = it },
            placeholder = { Text("Search...") }
        )
        
        LazyColumn {
            items(filtered) { item ->
                Text(item, modifier = Modifier.padding(8.dp))
            }
        }
    }
}

14. remember + LaunchedEffect (для side-effects)

@Composable
fun DataFetcher(userId: Int) {
    var data by remember { mutableStateOf<String?>(null) }
    var isLoading by remember { mutableStateOf(false) }
    
    // LaunchedEffect выполняется один раз при изменении userId
    LaunchedEffect(userId) {
        isLoading = true
        data = api.fetchUser(userId)
        isLoading = false
    }
    
    when {
        isLoading -> Text("Loading...")
        data != null -> Text("User: $data")
        else -> Text("No data")
    }
}

15. Когда используешь remember?

Используй remember когда:

  • Нужно сохранить состояние между перерисовками
  • Нужно хранить MutableState
  • Нужно кэшировать дорогостоящие вычисления
  • Нужно сохранить ссылку на объект

НЕ используй remember когда:

  • Это параметр композиции (это уже состояние родителя)
  • Это вычисляемое значение без зависимостей
  • Нужно сохранить при пересоздании (используй rememberSaveable)

Итог

  • remember сохраняет значение между перерисовками
  • Без remember переменные переинициализируются
  • remember { mutableStateOf() } — основной паттерн для состояния
  • remember(key1, key2) — пересчитывает при изменении ключей
  • rememberSaveable — сохраняет при пересоздании Activity
  • LaunchedEffect + remember для side-effects и асинхронных операций
Для чего нужна функция remember в Jetpack Compose? | PrepBro