Предположим, у нас есть дочерний компонуемый элемент, представляющий пользовательский переключатель, и мы хотим сохранить его неизменяемым, поэтому нам нужно для передачи исходного состояния, а также лямбды для изменения источника истины при переключении переключателя пользователем:
Код: Выделить всё
@Composable
fun CustomSwitch(
title: String? = null,
checked: Boolean = false,
onSwitchChanged: ((Boolean) -> Unit)? = null
){
//...
}
Код: Выделить всё
@Composable
fun PreferencesCard(
switch1Title: String? = null,
switch1Checked: Boolean = false,
OnSwitch1Changed: ((Boolean) -> Unit)? = null,
switch2Title: String? = null,
switch2Checked: Boolean = false,
OnSwitch2Changed: ((Boolean) -> Unit)? = null,
){
CustomSwitch(switch1Title, switch1Checked, OnSwitch1Changed)
CustomSwitch(switch2Title, switch2Checked, OnSwitch2Changed)
//Other composables
}
При таком подходе по мере продвижения вверх в иерархии составных элементов нам необходимо сохранить все дочерние параметры, в результате чего списки родительских параметров получаются очень длинными. Эта проблема характерна для декларативных инфраструктур пользовательского интерфейса и, например, в React она известна как Детализация свойств. Он создает сложный и необслуживаемый код, поскольку любое изменение в дочерних элементах (например, добавление нового параметра) приводит к изменениям во всех его родительских элементах. Это противоречит самой концепции инкапсуляции.
Если мы хотим сохранить неизменяемым составной родительский объект, одним из решений является инкапсуляция дочернего состояния и слушателей, чтобы списки параметров были короче:
Код: Выделить всё
data class PreferencesCardState(val switch1Title: String?, val switch1Checked: Boolean, val switch2Title: String?, val switch2Checked: Boolean)
interface PreferencesCardListener {
fun onSwitch1Changed(b: Boolean): Unit
fun onSwitch2Changed(b: Boolean): Unit
}
@Composable
fun PreferencesCard(
state: PreferencesCardState,
listener: PreferencesCardListener
){
CustomSwitch(state.switch1Title, state.switch1Checked, {value -> listener?.onSwitch1Changed(value)})
CustomSwitch(state.switch2Title, state.switch2Checked, {value -> listener?.onSwitch2Changed(value)})
//Other composables
}
Существует трюк, который предотвращает рекомпозицию из-за «нестабильных лямбда-выражений», то есть передача ссылок на методы вместо лямбда-выражений, но эти ссылки (часто указывающие на мутаторы, определенные в ViewModel), все равно необходимо передавать из корневого компонуемого объекта, если только мы не хотим передать всю ViewModel в качестве параметра (что является плохой практикой).
Так как же нам избежать сверления пропеллеров, сохраняя при этом все составные элементы неизменными?
Подробнее здесь: https://stackoverflow.com/questions/733 ... ck-compose
Мобильная версия