Как отделить пользовательский интерфейс и состояние приложения в Redux
При написании приложения react-redux
мне нужно сохранить как приложение, так и состояние пользовательского интерфейса в глобальном дереве состояний. Каков наилучший подход к его оформлению?
Допустим, у меня есть список предметов todo:
{
items: [
{ id: 1, text: 'Chew bubblegum' },
{ id: 2, text: 'Kick ass' }
]
}
Теперь я хочу, чтобы пользователи выбирали и расширяли элементы. Есть, по крайней мере, два варианта, как смоделировать форму состояния:
{
items: [
{ id: 1, text: 'Chew bubblegum', selected: true, expanded: false },
{ id: 2, text: 'Kick ass', selected: false, expanded: false }
]
}
Но это смешивает состояние пользовательского интерфейса (selected
и expanded
) с состоянием приложения. Когда я сохраняю список дел на сервере, я хочу сохранить только состояние приложения, а не состояние пользовательского интерфейса (в реальном приложении приложение, состояние пользовательского интерфейса может содержать состояние модальных диалогов, сообщения об ошибках, статус проверки и т.д.).
Другим подходом является сохранение другого массива для состояния пользовательского интерфейса элементов:
{
items: [
{ id: 1, text: 'Chew bubblegum' },
{ id: 2, text: 'Kick ass' }
],
itemsState: [
{ selected: true, expanded: false },
{ selected: false, expanded: false }
]
}
Затем вы должны объединить эти два состояния при рендеринге элемента. Я могу представить, что вы можете zip
использовать эти два массива в connect
для облегчения рендеринга:
const TodoItem = ([item, itemState]) => ...;
const TodoList = items => items.map(item => (<TodoItem item={item} />));
export default connect(state => _.zip(state.items, state.itemsState))(TodoList);
Но обновления состояния могут быть болезненными, потому что items
и itemsState
должны храниться в синхронизации:
- При удалении элемента необходимо удалить соответствующее itemState.
- При переупорядочивании элементов, itemsState также необходимо переупорядочить.
- Когда список элементов todo обновляется с сервера, необходимо сохранить идентификаторы в пользовательском интерфейсе и выполнить некоторую согласование.
Есть ли другой вариант? Или есть библиотека, которая помогает синхронизировать состояние приложения и пользовательского интерфейса?
Ответы
Ответ 1
Другой подход, основанный на normalizr:
{
ids: [12,11], // registry and ordering
data: {
11: {text: 'Chew bubblegum'},
12: {text: 'Kick ass'}
},
ui: {
11: { selected: true, expanded: false },
12: { selected: false, expanded: false }
}
}
Ответ 2
Я сейчас смотрю на это сам для побочного проекта. Я собираюсь приблизиться к нему, как и метод Рика выше. Данные {} служат источником истины, и вы используете это, чтобы вносить локальные изменения ui в (отражающие самое текущее состояние). Вам нужно объединить данные и ui вместе перед рендерингом, и я сам пробовал это в нескольких местах. Я скажу, что если держать в синхронизации, это не должно быть слишком плохо. В принципе, всякий раз, когда вы сохраняете/извлекаете данные, вы обновляете данные {} и очищаете ui {}, чтобы подготовиться к следующему варианту использования.