Псс! Вы знали, что ReasonReact – лучший способ работы с React?
React – замечательный инструмент для создания пользовательских интерфейсов. Но ReasonReact может сделать его еще лучше. Почему и как, расскажем дальше.
React в комбинации с JavaScript хорош, но не идеален. У этого альянса есть серьезные проблемы, которые может решить ReasonML. О каких проблемах речь?
React изначально не был разработан для JavaScript
Если вы внимательно посмотрите на React, то увидите, что некоторые из его основных положений чужды JavaScript. Прежде всего это иммутабельность, принципы функционального программирования и система типов.
Иммутабельность – один из основных принципов React. Если свойства или состояние приложения изменятся, последствия могут быть непредсказуемыми. В JavaScript из коробки иммутабельности нет, поэтому неизменяемость данных в React обеспечивается соглашениями и сторонними библиотеками, такими как immutableJS.
Приложения React – это совокупность функций. JavaScript, конечно, имеет ряд средств для функционального программирования, например, функции первого класса, но не является функциональным языком в целом. Когда мы хотим написать хороший декларативный код, приходится использовать внешние библиотеки, такие как Lodash/fp или Ramda.
В JavaScript нет статической типизации, поэтому в React мы используем PropTypes для ее имитации. Чтобы воспользоваться всеми преимуществами типов, нам снова нужно использовать внешние зависимости, такие как Flow и TypeScript.
Вы сами видите, что основные принципы React несовместимы с JavaScript.
Существует ли другой язык программирования, который был бы более совместим с React? Да, и это ReasonML.
В Reason есть встроенная реализация иммутабельности и мощная система типов. Кроме того, он основан на OCaml, языке функционального программирования, и наследует от него множество полезных фич.
Reason совместим с основными принципами React.
Reason
Это не новый язык, а комбинация альтернативного JavaScript-подобного синтаксиса и набора инструментов для OCaml, функционального языка, существующего уже более 20 лет. Reason был создан разработчиками Facebook, которые уже использовали OCaml в своих проектах (Flow, Infer).
Reason, с его C-подобным синтаксисом, делает OCaml доступным для программистов, пришедших из таких языков, как JavaScript или Java. По сравнению с OCaml, у него лучшая документация и активно растущее сообщество. Кроме того,он легко интегрируется в существующие кодовые базы JavaScript.
OCaml для Reason является базовым языком, из которого он заимствовал семантику и замечательные опции вроде системы типов и сопоставления с образцом. Теперь все эти возможности имеют JavaScript-подобный синтаксис:
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)) };
Хотя мы используем в этом примере сопоставление с шаблоном, код все равно очень похож на JS, не так ли?
Тем не менее, в браузерах по-прежнему можно использовать только JavaScript, следовательно Reason нужно каким-то образом скомпилировать.
BuckleScript
У Reason есть мощный компилятор BuckleScript, который на выходе создает читаемый и производительный JavaScript, устранив весь мертвый код. Если не все члены вашей команды знакомы с Reason, они все равно смогут читать скомпилированный вариант.
Сходство с JavaScript настолько велико, что часть кода вообще не нуждается в изменении. Таким образом, вы можете пользоваться преимуществами статически типизированного языка, ничего не переписывая.
let add = (a, b) => a + b; add(6, 9);
Такой код допустим и в Reason, и в JavaScript.
BuckleScript поставляется с четырьмя библиотеками: стандартной, называемой Belt (стандартная библиотека OCaml недостаточна), и привязками к JavaScript, Node.JS и, DOM API.
Поскольку BuckleScript основан на компиляторе OCaml, вы получаете невероятно быструю компиляцию, намного быстрее Babel и в несколько раз быстрее TypeScript.
Давайте скомпилируем написанный на Reason алгоритм FizzBuzz из рассмотренного примера в JavaScript.
Полученный код вполне читаем, как будто его написал JavaScript-разработчик.
Reason может компилироваться не только в JS, но и в машинный код, и в байт-код. Таким образом, одно и то же написанное на Reason приложение можно запустить в браузере на разных операционных системах, а также на мобильных устройствах Android и iOS. Например, существует игра Gravitron, написанная на Reason, которая работает на всех этих платформах.
Функциональная совместимость с JavaScript
BuckleScript также обеспечивает совместимость с JavaScript. Вы можете не только вставить рабочий JS-код в кодовую базу Reason, но и взаимодействовать с ним. Следовательно, можно сделать и наоборот, интегрировав Reason-код в существующий JavaScript-проект. Вам также будут доступны все npm-пакеты! Например, в одном приложении можно объединить Reason, Flow и TypeScript.
Однако, все это не так просто. Чтобы использовать JavaScript-библиотеки или модули в Reason, необходимо сначала перенести их с помощью привязок (Reason bindings). Другими словами, чтобы воспользоваться системой типов, эти типы нужно внедрить в нетипизированный JavaScript-код.
Если вам нужна какая-то JS-библиотека, сначала проверьте, была ли она уже перенесена на Reason. Сделать это можно в базе данных Reason Package Index (Redex). Все библиотеки отсюда можно просто устанавливать как зависимости и сразу же использовать.
Однако, если вы не нашли нужную библиотеку, придется самостоятельно написать привязку для нее. Специальное предупреждение для начинающих Reason-программистов: имейте в виду, что это одна из самых сложных вещей в экосистеме.
Необязательно создавать привязку для библиотеки в целом. Если вам необходимы лишь отдельные компоненты, будет разумно привязать только их.
ReasonReact
Закончив с вводными сведениями, переходим, наконец, непосредственно к библиотеке ReasonReact и причинам, по которым следует использовать именно ее.
Мы уже говорили о том, что Reason больше, чем JavaScript, совместим с React. Почему так вышло? Да потому что React изначально был разработан для Reason, точнее, для OCaml.
Дорога к ReasonReact
Первый прототип React в Facebook был написан на языке StandartML (Standart Meta Language), двоюродном брате OCaml, а затем переписан на самом OCaml.
Позднее React был адаптирован для JavaScript. Зачем? Потому что JavaScript – главный язык клиентского веба и было бы неразумно создавать новый интерфейсный инструмент на OCaml. Это сработало, и React в связке с JavaScript завоевал огромную популярность.
Мы привыкли воспринимать React как JS-библиотеку. Вместе с другими инструментами и языками – Elm, Redux, Recompose, Ramda и PureScript – он активно продвигает функциональное программирование на JavaScript. С развитием Flow и TypeScript становится популярной также статическая типизация. В результате функциональная парадигма со статическими типами стала массовым стандартом в мире фронтенда.
В 2016 году Bloomberg создал опенсорсный компилятор BuckleScript, преобразующий OCaml в JavaScript. Это позволило писать безопасный фронтенд-код с использованием мощной системы типизации.
Сложившаяся ситуация была идеальной для возвращения к первоначальной идее React.
Разработчики Facebook взяли семантику OCaml и синтаксис JavaScript и создали Reason. Они также создали оболочку для React – библиотеку ReasonReact – с дополнительными функциями, такими как инкапсуляция принципов Redux в компонентах с отслеживанием состояния. React вернулся к истокам.
React + Reason
Когда появился React, мы скорректировали JavaScript под его нужды путем введения дополнительных библиотек и инструментов. Это привело к увеличению количества зависимостей для наших проектов. Многие из этих библиотек находятся в стадии разработки и регулярно вносят изменения, которые приходится отслеживать и проверять. JavaScript-разработка стала сложнее.
Среднестатистическое React-приложение имеет, по крайней мере, следующие зависимости:
- Flow/TypeScript для статической типизации;
- immutableJS для иммутабельности;
- ReactRouter для маршрутизации;
- Prettier для форматирования;
- ESLint для линтинга;
- Ramda/Lodash для вспомогательных функций.
Давайте теперь поменяем JavaScript React на ReasonReact. Нам все еще нужны все эти зависимости?
- статическая типизация – встроенная;
- иммутабельность – встроенная;
- маршрутизация – встроенная;
- форматирование – встроенное;
- линтинг – встроенный;
- вспомогательные функции – встроенные.
Узнать об этих встроенных возможностях больше вы можете здесь.
В приложении ReasonReact эти (и ряд других) зависимости не нужны, поскольку многие важные функции, упрощающие разработку, уже включены в сам язык. Таким образом, поддерживать проект станет гораздо проще.
Спасибо зрелому и стабильному OCaml, который надежно работает уже больше 20 лет.
В итоге
У создателей Reason было два варианта. Первый – взять JavaScript и улучшить его, борясь по пути с историческим грузом языка. Второй – взять зрелый высокопроизводительный OCaml и модифицировать его так, чтобы он напоминал JavaScript.
React основан на принципах OCaml, поэтому вам будет комфортнее работать с ним, если вы будете использовать Reason. ReasonReact – это безопасный способ создания компонентов благодаря надежной системе типов и отсутствию множества legacy-проблем JavaScript.
Что дальше?
Если вы пришли из мира JavaScript, вам будет легко разобраться с Reason благодаря сходству синтаксиса. Если вы программировали на React, вам будет еще проще, ведь ReasonReact очень похож на сам React.
Лучше всего начинать работу с Reason постепенно. Например, вы можете создать ReasonReact-компонент и ввести его в свое React-приложение, написанное на JavaScript (или наоборот).
Подобный поэтапный подход был выбран разработчиками Facebook при создании приложения Facebook Messenger.
Чтобы изучить основы ReasonReact на практике, попробуйте самостоятельно написать игру Tic Tac Toe.
Оригинальная статья: Psst! Here’s why ReasonReact is the best way to write React, David Kopal