Разработка React-приложений с использованием ReasonReact

Вы применяете React для создания пользовательских интерфейсов? Автор материала, перевод которого мы публикуем, говорит, что он тоже работает с React. Здесь он хочет рассказать о том, почему для написания React-приложений стоит использовать ReasonML.

React — это очень хороший инструмент для разработки интерфейсов. Можно ли сделать его ещё лучше? Для того чтобы улучшить работу с React, сначала надо понять его основные проблемы. В частности, проблему, у истоков которой лежит тот факт, что React — это JavaScript-библиотека.

React и JavaScript

Если присмотреться к React, то можно заметить, что некоторые из принципов, положенные в основу этой библиотеки, чужды для JavaScript. В частности, мы говорим об иммутабельности, о принципах функционального программирования и о системе типов.

Иммутабельность — это один из базовых принципов React. Мутации свойств компонентов или состояния приложения весьма нежелательны, так как подобное может привести к непредсказуемым последствиям. В JavaScript нет стандартных механизмов для обеспечения иммутабельности. Структуры данных делают иммутабельными либо придерживаясь неких соглашений, либо используя библиотеки наподобие immutable-js.

Библиотека React основана на принципах функционального программирования, так как React-приложения представляют собой композиции функций. Хотя в JavaScript имеются некоторые возможности функционального программирования, такие, как функции первого класса, функциональным языком программирования он не является. Если на JavaScript нужно писать хороший декларативный код, приходится прибегать к сторонним библиотекам вроде Lodash/fp или Ramda.

А что не так с системой типов? В React имеется концепция PropTypes. Её используют для имитации типов в JavaScript, так как этот язык, сам по себе, не является статически типизированным. Для того, чтобы пользоваться в JS выгодами статической типизации, опять же, приходится прибегать к сторонним инструментам, таким, как Flow и TypeScript.

Сравнение React и JavaScript

Как видите, JavaScript не совместим с базовыми принципами React.

Существует ли язык программирования, который лучше JavaScript согласуется с React?
На данный вопрос можно дать положительный ответ. Этот язык — ReasonML.

В Reason реализована иммутабельность. Так как он основан на OCaml, функциональном языке программирования, соответствующие возможности также оказываются встроенными в Reason. В этом языке, кроме того, присутствует собственная система типов, подходящая для React.

Сравнение React, JavaScript и Reason

Получается, что Reason совместим с базовыми принципами React.

Reason

Reason — это не новый язык. Он представляет собой альтернативный, напоминающий JavaScript, синтаксис и набор инструментов для OCaml — функционального языка программирования, который существует уже более 20 лет. Reason был создан разработчиками из Facebook, которые уже использовали OCaml в своих проектах (Flow, Infer).

OCaml

С-подобный синтаксис Reason делает OCaml доступным для программистов, которые знакомы с такими распространёнными языками, как JavaScript или Java. Reason даёт разработчику более качественную, в сравнении с OCaml, документацию, вокруг него сложилось постоянно растущее сообщество энтузиастов. Кроме того, то, что написано на Reason, несложно интегрировать с существующими JS-проектами.

Reason

Основой Reason является OCaml. Reason имеет ту же семантику, что и OCaml, различается лишь синтаксис. Это означает, что Reason даёт возможность писать OCaml-код, используя JavaScript-подобный синтаксис. В результате в распоряжении программиста оказываются такие замечательные возможности OCaml, как строгая система типов и механизм сопоставления с образцом (pattern matching).

Взглянем на фрагмент Reason-кода для того, чтобы ознакомиться с его синтаксисом.

let fizzbuzz = (i) =>
  switch (i mod 3, i mod 5) {
  | (0, 0) => "FizzBuzz"
  | (0, _) => "Fizz"
  | (_, 0) => "Buzz"
  | _ => string_of_int(i)
  };
for (i in 1 to 100) {
  Js.log(fizzbuzz(i))
};

Хотя в этом фрагменте используется механизм сопоставления с образцом, он остаётся весьма похожим на JavaScript.

Единственным языком, который работает в браузерах, является JavaScript, поэтому, для того, чтобы писать для браузеров на каком бы то ни было языке, нам надо компилировать его в JavaScript.

BuckleScript

Одной из интереснейших возможностей Reason можно назвать компилятор BuckleScript, который берёт код, написанный на Reason и преобразует его в читабельный и производительный JS-код, кроме того, неплохо очищая его от неиспользуемых конструкций.

BuckleScript

Читабельность результатов работы BuckleScript придётся кстати в том случае, если вы работаете в команде, в которой не все знакомы с Reason. Эти люди, по крайней мере, смогут читать результирующий JS-код.

Код на Reason иногда так похож на JS-код, что компилятору вовсе не нужно его преобразовывать. Благодаря такому положению дел можно наслаждаться благами статической типизации Reason и писать код, выглядящий так, будто он написан на JavaScript.

Вот пример кода, который будет работать и в Reason и в JavaScript:

let add = (a, b) => a + b;
add(6, 9);

BuckleScript поставляется с четырьмя библиотеками. Это — стандартная библиотека, называемая Belt (стандартной библиотеки OCaml тут недостаточно), и привязки для JavaScript, Node.js и для API DOM.

Так как BuckleScript основан на компиляторе OCaml, компиляция оказывается очень быстрой — гораздо быстрее чем у Babel и в несколько раз быстрее чем у TypeScript.

Скомпилируем с помощью BuckleScript вышеприведённый фрагмент Reason-кода, содержащий функцию fizzbuzz(), в JavaScript.

Компиляция Reason-кода в JavaScript с помощью BuckleScript

Как видите, JS-код оказался вполне читаемым. Выглядит он так, как будто написан человеком.

Программы, написанные на Reason, компилируются не только в JavaScript, но и в нативный код, и в байт-код. В результате, например, можно написать приложение на Reason и запустить его в браузере, на MacOS, на смартфонах, работающих под управлением Android и iOS. Существует игра Gravitron, написанная Джаредом Форсайтом на Reason. Её можно запускать на всех вышеупомянутых платформах.

Организация взаимодействия с JavaScript

BuckleScript даёт возможность организации взаимодействия Reason и JavaScript. Это означает не только возможность использования рабочего JS-кода в кодовой базе Reason, но и возможность взаимодействия кода, написанного на Reason, с этим JavaScript-кодом. Как результате, код, написанный на Reason, легко поддаётся интеграции в существующие JS-проекты. Более того, в Reason-коде можно использовать JavaScript-пакеты из NPM. Например, можно создать проект, в котором совместно используются Flow, TypeScript и Reason.

Однако всё не так уж и просто. Для того чтобы использовать JavaScript-код или библиотеки в Reason, их сначала надо портировать с использованием привязок (биндингов) Reason. Другими словами, нам, для того, чтобы воспользоваться строгой системой типов Reason, нужны типы для обычного JavaScript-кода.

Если вам нужно воспользоваться какой-нибудь JavaScript-библиотекой в Reason-коде, сначала стоит обратиться к Reason Package Index (Redex) и узнать, была ли эта библиотека уже портирована в Reason. Проект Redex представляет собой каталог библиотек и инструментов, написанных на Reason и JavaScript-библиотек с Reason-привязками. Если вам удалось найти в этом каталоге нужную библиотеку, её можно установить как зависимость и использовать в Reason-приложении.

Если же найти нужную библиотеку не удалось, вам придётся самостоятельно написать биндинги. Если вы только начинаете знакомство с Reason, учтите, что писать биндинги — это задача не для новичка. Это — одна из самых сложных задач, из тех, что приходится решать тем, кто программирует на Reason. На самом деле, это — тема для отдельной статьи.

Если вам нужен лишь некий ограниченный функционал какой-нибудь JavaScript-библиотеки, вам не нужно писать привязки для всей такой библиотеки. Сделать это можно только для необходимых функций или компонентов.

ReasonReact

В начале материала мы говорили о том, что он посвящён разработке React-приложений с использованием Reason. Заниматься этим можно благодаря библиотеке ReasonReact.

Возможно, сейчас вы думаете: «Мне всё ещё непонятно — почему надо писать React-приложения на Reason». Однако мы уже обсудили основную причину использования связки React и Reason, которая заключается в том, что React лучше совместим с Reason чем с JavaScript. Почему это так? Всё дело в том, что React был создан в расчёте на Reason, или, точнее, в расчёте на OCaml.

Путь к ReasonReact

Первый прототип React был разработан Facebook и был написан на Standard Meta Language (StandardML), на языке, который является родственником OCaml. Затем React перевели на OCaml, кроме того, React перенесли на JavaScript. Сделано это было из-за того, что весь веб использовал JavaScript и, вероятно, неразумным было бы делать заявления вроде: «А теперь мы будем писать UI на OCaml». Перевод React на JavaScript себя оправдал и привёл к широкому распространению этой библиотеки.

Как результат, все привыкли воспринимать React в виде JS-библиотеки. React, а также другие библиотеки и языки, такие как Elm, Redux, Recompose, Ramda, и PureScript, способствовали популяризации функционального стиля программирования в JavaScript. А благодаря распространению Flow и TypeScript в JavaScript стала популярна и статическая типизация. В итоге парадигма функционального программирования с использованием статических типов стала главенствующей в мире разработки фронтенда.

В 2006 году компания Bloomberg создала и перевела в разряд опенсорсных проектов компилятор BuckleScript, который преобразует OCaml в JavaScript. Это позволило им писать более качественный и безопасный фронтенд-код, используя строгую систему типов OCaml. Они взяли оптимизированный и очень быстрый компилятор OCaml и заставили его генерировать код на JavaScript.

Популярность функционального программирования и выпуск BuckleScript создали идеальный климат, который позволил Facebook вернуться к исходной идее React — библиотеки, которая изначальна была написана на StandardML.

ReasonReact

Они смешали семантику OCaml с синтаксисом JavaScript и создали Reason. Кроме того, они создали Reason-обёртку для React, представленную в виде библиотеки ReasonReact, которая обладает дополнительными функциями, такими, как инкапсуляция принципов Redux в компонентах с состоянием. Сделав это, они вернули React к его истокам.

О возможностях React в Reason

Когда библиотеку React переводили на JavaScript, возможности языка подгоняли под нужды React за счёт создания различных библиотек и инструментов. Подобный подход, в частности, означает необходимость в большом числе зависимостей для проектов. Уж не будем говорить о том, что подобные библиотеки постоянно развиваются, и в них регулярно происходят изменения, делающие их новые версии несовместимыми со старыми. Как результат, разработчику приходится очень серьёзно и осторожно относиться к обслуживанию библиотек, от которых зависят его проекты.

Это добавляет дополнительный уровень сложности в JavaScript-разработку. Например, типичное React-приложение обычно содержит, как минимум, зависимости, которые можно видеть на следующем рисунке.

Зависимости типичного React-приложения

Вот какие задачи решают эти зависимости:

  • Статическая типизация — Flow/TypeScript.
  • Иммутабельность — ImmutableJS.
  • Маршрутизация — ReactRouter.
  • Форматирование кода — Prettier.
  • Линтинг — ESLint.
  • Вспомогательные функции — Ramda/Lodash.

Теперь воспользуемся, вместо React для JavaScript, библиотекой ReasonReact. Нужны ли нам, при таком подходе, все эти зависимости?

Переход на ReasonReact

Проанализировав тот же список задач, которые раньше решались с помощью дополнительных средств, мы выясним, что все их можно решить с помощью встроенных средств ReasonReact.

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

Всё это оказывается возможным благодаря использованию языка OCaml, которому уже более 20 лет. Это зрелый язык, базовые принципы и механизмы которого проверены временем и стабильны.

Что дальше?

Если вы родом из мира JavaScript, вам будет несложно начать работу с Reason благодаря тому, что синтаксис этого языка похож на JavaScript. Если вы раньше писали React-приложения, перейти на Reason вам будет ещё легче, так как вы можете, при работе с ReasonReact использовать все свои познания в области React. В основе ReasonReact лежит та же модель мышления, что и в основе React, процесс работы с ними так же очень схож. Это означает, что при переходе на Reason вам не придётся начинать с нуля. Вы разберётесь с Reason в процессе работы.

Лучший способ начать использовать Reason в своих проектах заключается в том, чтобы постепенно вводить в них фрагменты, написанные на Reason. Как уже было сказано, Reason-код можно использовать в JS-проектах, равно как и JS-код в Reason-проектах. Этот подход применим и при использовании ReasonReact. Можно взять ReasonReact-компонент и использовать его в традиционном React-приложении, написанном на JavaScript.

Именно такой вот инкрементальный подход был выбран разработчиками Facebook, которые широко использовали Reason при разработке мессенджера Facebook.

Итоги

У создателей Reason было два варианта действий. Первый заключался в том, чтобы взять JavaScript и как-то его улучшить. Если бы они избрали этот путь — им пришлось бы иметь дело с историческими недостатками JS.

Они, однако, избрали второй путь, связанный с OCaml. Они взяли OCaml — зрелый язык, обладающий отличной производительностью, и модифицировали его так, чтобы он стал похожим на JavaScript.

React тоже основан на принципах OCaml. Именно поэтому писать React-приложения гораздо легче и приятнее с использованием Reason. Работа с React в Reason предлагает более стабильный и безопасный подход к созданию React-компонентов, так как строгая система типов страхует разработчика и ему не приходится сталкиваться с большинством исторических проблем JavaScript.

Вам также может понравиться

About the Author: admin

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *