- ccorcos:react-ui
- Предыдущая статья: Веселье: React.js + Coffeescript
Когда я начал создавать Shindig, я понял, что все состояние просмотра моих компонентов было потеряно, когда я переходил на другую вкладку, а затем обратно. Это особенно ужасно иногда. Представьте, что вы указали поля поиска, прокрутили список вглубь, щелкнули элемент в этом списке, затем нажали назад, чтобы вернуться к списку, и все ваши поля поиска исчезли, и вы вернулись в начало списка. . Это просто неприемлемо для любого качественного приложения.
Я начал спрашивать на форумах и продолжал получать однострочные ответы: Flux. Хотя Flux интересен, особенно для обработки данных с сервера, меня не устроило его простое запоминание некоторого состояния и scrollTop элемента.
Вместо использования Flux я придумал действительно простой способ сохранения всего этого состояния в глобальном изменяемом объекте состояния, который передается по иерархии компонентов.
Например, Scroll — это простой компонент, который поддерживает позицию прокрутки списка. Он проверяет экземпляр, когда он монтируется, чтобы установить scrollTop, а когда он размонтируется, он мутирует экземпляр, чтобы запомнить scrollTop на время монтирования компонента.
Scroll = createView componentDidMount: -> @getDOMNode().scrollTop = @props.instance.scrollTop or 0 componentWillUnmount: -> @props.instance.scrollTop = @getDOMNode().scrollTop render: -> div className: 'scroll' @props.children
Родительский компонент может передавать экземпляры своим дочерним элементам как свойство собственного экземпляра.
EventList = createView componentWillMount: -> @props.instance.scroll = @props.instance.scroll or {} renderEventItem: (event) -> EventItem({event}) render: -> Scroll instance: @props.instance.scroll @props.events.map(@renderEventItem)
В конце концов, все состояние приложения поднимается до одного экземпляра верхнего уровня.
Meteor.startup -> instance = {} React.render(App({instance}), document.body)
Вот это действительно круто. Все состояние пользовательского интерфейса хранится в одной переменной. Вы могли заметить, что перезагрузка в режиме реального времени — это боль — каждый раз, когда страница перезагружается, когда вы пишете какой-то код, вы теряете все состояние своего пользовательского интерфейса. На самом деле мы можем сериализовать и сохранять эти данные в localStorage в браузере между перезагрузками в реальном времени, сохраняя состояние пользовательского интерфейса во время разработки и во время отправки горячего кода. Мы используем тот же Meteor API, что и с Session/ReactiveDict.
instance = Meteor._reload.migrationData('react-ui-instance') or {} Meteor._reload.onMigrate 'react-ui-instance', -> return [true, instance]
Рефакторинг
Единственная плохая сторона этого паттерна заключается в том, что он связан с мутациями. Изменение данных — это антишаблон. Но иногда мутация неизбежна, и в этом случае лучше всего ограничить мутацию функцией с неизменяемым интерфейсом. Это именно то, что я сделал в виде миксина.
Scroll = createView mixins: [InstanceMixin] componentDidMount: -> @getDOMNode().scrollTop = @props.instance.scrollTop or 0 save: -> scrollTop: @getDOMNode().scrollTop render: -> div className: 'scroll' @props.children EventList = createView mixins: [InstanceMixin] renderEventItem: (event) -> EventItem({event, key:event.id}) render: -> Scroll instance: @childInstance('scroll') @props.events.map(@renderEventItem)
Используя InstanceMixin, мы также можем сохранять снимок всего пользовательского интерфейса каждый раз, когда вызывается сохранение, чтобы мы могли перематывать историю! Это довольно круто в теории, но, честно говоря, я не нашел это ужасно полезным.
Это всего лишь одна из функций моего пакета Meteor, ccorcos:react-ui.
Однако я должен признать, что если бы мне пришлось делать это снова, я бы, вероятно, просто использовал Redux. Его не было, когда я начал этот проект, но он очень похож и имеет гораздо большую поддержку сообщества с помощью плагинов Chrome DevTools и т. д.
Теперь, когда у нас есть средства сохранения экземпляров компонентов между монтированиями, мы можем создать контроллер представления вкладок, который поддерживает положение прокрутки каждого представления при переключении между вкладками. Это тема следующей статьи.
- Следующая статья: Shindig: Контроллер представления вкладок React