ClojureScript/OM: обновление состояния компонента из другого компонента — или: работа с глобальным состоянием

Я начинаю работу с om и ClojureScript с очень простым приложением.

Мое глобальное состояние приложения выглядит так:

(def app-state (atom {:animals [ {:name "dog" :img "pic01.jpg"}
                                 {:name "cat" :img "pic02.jpg"}
                                 {:name "mouse" :img "pic03.jpg"}
                                 {:name "camel" :img "pic04.jpg"}]}))

Свойство name каждой хэш-карты внутри вектора «животные» преобразуется в структуру списка HTML (например, LI-тег) с помощью компонента om, который я назвал «меню». Каждая запись отображается другим компонентом, называемым «записью». (например, как элемент UL). Всякий раз, когда пользователь наводит курсор на одну из записей списка, внешний вид записи меняется (возможно, меняется фон). Я фиксирую эти текущие состояния внутри компонента входа, который я инициализирую через om/IInitState.

Это работает до сих пор. Теперь я хочу добавить еще один компонент, который называется «дисплей». Он должен иметь возможность отображать изображения, связанные с именами животных, в глобальном состоянии всякий раз, когда пользователь щелкает запись в списке. Я спрашиваю себя, что было бы лучшим способом решить эту проблему.

Я вижу две возможности:

Сохранение локального состояния в компоненте «отображение», которое обновляется событием onClick из компонента «запись». Здесь мой вопрос будет таким: как я могу обновить состояние компонента из другого компонента?

Или введение другого свойства в глобальное состояние, которое может называться: «active_section», которое обновляется событием onClick в компоненте ввода и считывается компонентом «отображение». Но так ли это необходимо?


person Anton Harald    schedule 28.12.2015    source источник
comment
Похоже, вы начинаете работать с Om, как раз когда Om/Next заменяет его.   -  person Chris Murphy    schedule 29.12.2015


Ответы (2)


Не уверен, что понимаю ваши требования на 100%, но добавлю свои 2 цента.

В общем, я бы избегал дизайна, в котором один компонент каким-то образом обновляет локальное состояние в другом компоненте. Это создаст тесную связь между компонентами, что, вероятно, не совсем то, что вам нужно. Гораздо лучше проектировать/разрабатывать свои компоненты так, чтобы у них было как можно меньше знаний о других компонентах.

Лучший подход к приложениям, основанным на реакции, — сохранить ваше состояние в глобальном атоме состояния. В этом случае один компонент (компонент меню?) устанавливает значение свойства :visible или :current в вашем глобальном состоянии, которое указывает текущее животное. Ваш другой компонент будет отображать животное на основе записи с этим свойством, установленным в true.

Другим преимуществом этого способа является то, что если вы решите добавить дополнительные компоненты, которые должны работать с текущим «животным», он также может использовать эту информацию.

Хранение всех изменений состояния, которые могут вызвать рендеринг DOM, в одном месте также может упростить отладку. Кроме того, проверьте om-next (есть быстрый старт tutorial), так как у него есть новый подход к настройке/получению состояния, который обещает сделать вещи намного проще, чем старый подход «курсор».

person Tim X    schedule 29.12.2015
comment
Спасибо Тим, это было именно то рассмотрение, которое я искал. очень полезно. om/next будет следующей вещью, которую я проверю. но шаг за шагом. - person Anton Harald; 29.12.2015

Я использую два разных подхода. Во-первых, компонент должен «транслировать» свое состояние в виде сообщения. Например, у меня есть компонент календаря, который «транслирует» его «текущую дату». Когда кто-то нажимает на другую дату, он транслирует эту новую дату. Любой компонент может прослушивать это сообщение и обновлять себя по мере необходимости.

Мой второй подход заключается в том, чтобы компоненты передавали сообщения «другому» компоненту. Он делает это путем широковещательной передачи «типа» сообщения, которое прослушивает другой компонент. Например, у меня есть компонент, который хочет редактировать клиента. Он транслирует «клиента», которого он хочет отредактировать, в «компонент редактирования клиента». «Компонент редактирования клиента» решает, может ли он отображать клиента или нет, и обрабатывает редактирование. Если он решает сохранить изменения, транслируется сообщение «сохранить». Что-то в списке сообщений «сохранить» обрабатывает запрос и передает результат «сохранения». Компоненты, которые отображают информацию о клиенте, обрабатывают «обновленное» сообщение клиента и отображают изменения.

Единственная связь существует между шиной сообщений и сообщениями. Все это реализовано с помощью core.async.

Вопрос, который вы должны решить заранее, заключается в том, иметь ли более одной шины (канала) или нет. Другая проблема заключается в том, что компонентам необходимо закорачивать сообщения, не адресованные им.

У меня есть специальный компонент, который прослушивает ВСЕ сообщения в целях отладки.

Я бы поостерегся привязывать все ваши глобальные данные непосредственно к компонентам. Я предпочитаю думать о глобальных данных как о базе данных, а не о внутренних данных компонента.

person Chaos Rules    schedule 29.12.2015