TL; DR (иначе, просто скажите мне, в чем вы ошибались)
- Передавать
appState
всем компонентам - не лучшая идея.appState
содержит неразрешенные возможные состояния, о которых отдельные компоненты обычно не заботятся, но которые вам все равно придется обрабатывать, поскольку ReasonML - это строго типизированный язык. - Вместо передачи состояния передайте
ctx
(контекст). Мой текущий подход заключается в передачеctx
записи каждому компоненту, который содержит разрешенную информацию, производную из состояния, которая требуется конкретному компоненту . Это позволяет компоненту функционировать с определенными знаниями о контексте, в котором он будет отображаться. - Передача
appSend
всем компонентам (как и раньше) - это нормально - это просто функция, с помощью которой мы влияем на состояние приложения.
И более подробно…
Я писал о методе поддержки состояния приложения в ReasonReact еще в апреле, и с тех пор я работал с ReasonML намного больше, завершив преобразование кодовой базы Тураку с ES6 в Reason, и оказалось, что мой подход, описанный в предыдущей статье, не работал так хорошо, как я ожидал.
Передавать состояние приложения как appState
- плохая идея с ReasonML. Передавать appSend
вроде нормально.
Почему? Что ж, одна из основных задач функционального программирования - сделать недопустимые состояния непредставимыми. Проще говоря, это означает, что структуры, которые определяют и хранят наши данные, не должны допускать возможности неправильного состояния. Этого практически невозможно достичь с помощью языков с динамической типизацией, и если вы уже не поняли этого принципа, сделайте себе одолжение и посмотрите потрясающую лекцию Ричарда Фельдмана под названием Сделать невозможные состояния невозможными.
Я продолжу предполагать, что вы смотрели видео.
Один из инструментов, который ReasonML дает нам для описания вещи, которая может быть одним из набора вещей, называется Variant. В определении состояния приложения Тураку есть типы, которые выглядят примерно так (упрощенно):
Глядя на базовый тип state
, довольно легко сказать, что мы описали состояние нашего пользователя в приложении как всегда как одно из двух - либо пользователь вышел из системы (и находится на общедоступной странице) , или пользователь вошел в систему (и имеет некоторые соответствующие пользовательские данные).
Варианты позволяют компилятору ReasonML гарантировать, что всякий раз, когда мы обрабатываем значение типа вариант, учитывались все его возможности. Например, в корневом компоненте, когда мы пытаемся определить, какое представление отображать, мы могли бы использовать switch
, например:
Компилятор можно настроить на выдачу предупреждений или ошибок, если мы забыли обработать все определенные варианты, которыми может быть. Вы заметите, что я еще не передаю appState
ни одному из этих компонентов. Итак, давайте попробуем это с компонентом Dashboard
.
Dashboard
содержит основной пользовательский интерфейс, с которым должен взаимодействовать зарегистрированный пользователь. Отправим appState
и appSend
…
… А затем загляните внутрь Dashboard
, чтобы увидеть, как мы можем отобразить список доступных команд:
Теперь проблема должна быть очевидна. appState
является вариантом (или может содержать вложенные варианты), и его содержимое можно получить только через сопоставление с образцом. Из-за этого компонент вынужден обрабатывать все возможные случаи, хотя мы знаем, что панель мониторинга никогда не будет отображаться без входа пользователя в систему.
К счастью, исправить это просто. Это необходимо для того, чтобы не передавать состояние приложения.
Состояние приложения - это структура, которая представляет все возможные состояния, в которых может находиться приложение. Однако процесс визуализации внутреннего компонента включает сжатие этих возможностей. Что мы должны сделать, так это определить контекст, в котором ожидается рендеринг компонента.
В приведенном выше примере для компонента Dashboard
бессмысленно отображать для вышедшего из системы пользователя, поэтому исправление состоит в том, чтобы гарантировать, что ожидаемый контекст компонента включает информацию, доступную для вошедшего в систему пользователя ...
Теперь компилятор убедится, что компонент вызывается с допустимым контекстом:
Вот и все ... за исключением ... похоже, что мы вернулись во времена бурения опор, против чего я выступал в своей последней статье.
Да, но только частично. Обратите внимание, что мы все еще передаем appSend
, что позволяет нам исключить функции обратного вызова. appSend
предоставляет компонентам доступ ко всем действиям редуктора состояния приложения.
Здесь также появляется запись ctx
. Я обнаружил, что очень удобно обернуть все в одну запись, чтобы я мог передавать ее функциям - это также помогает избежать худших последствий сверления опор - там, где вам придется нанизать новые свойства на функции внутри компонентов, чтобы доставить их туда, где они должны быть. Оборачивая реквизиты в ctx
и рассматривая его как набор значений, к которым можно обращаться везде, где это необходимо, мы ограничиваем нарезание резьбы / сверление точками входа и выхода компонентов.
Также имеет смысл увеличивать запись ctx
, поскольку она передается в более глубокие компоненты, при этом родительские компоненты разрешают больше возможностей состояния приложения и передают более определенный контекст. своим детям.
Очевидно, что использование записи ctx
необязательно. Передача отдельных опор также работает, и выбор между обертыванием опор или оставлением их неупакованными, по-видимому, является решением между уменьшением накладных расходов на бурение опор или улучшением чистоты места вызова компонентов.
Так какой вывод?
Передача appState
была шаблоном, который хорошо работал с динамическими языками. Фактически, если мы структурируем состояние так, как если бы мы его записали на динамическом языке - без использования функций, которые дает нам строгая типизация (например, вариантов), то можно продолжать использовать appState
.
Но, если мы правильно используем ReasonML с намерением сделать недопустимые состояния непредставимыми, тогда старых шаблонов окажется недостаточно. Это мое частичное опровержение возникло из-за лучшего понимания того, как писать функциональный код.
Кредиты
Искусство Рекхи Соман: www.rekhasoman.com
Первоначально опубликовано на blog.harigopal.in 8 сентября 2018 г.