← Назад к вопросам
Для чего нужна функция 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 и асинхронных операций