Автор оригинала: Peter de Croos.
Было несколько попыток создавать альтернативы в интерфейсах, которые компилируют JavaScript. Я пробовал большинство из них в различных степенях:
- Я любил Clojurecript, но история взаимодействия была сложной.
- ELM убил все мои ошибки времени выполнения, но это была боль, необходимая взломать вещи или звонить в JS, когда она не подходит, что я пытался сделать.
- Tymdercript добавил хорошее количество типа безопасностью, но она была медленной и «BoilerPlate-Y».
Причина, однако, имеет лучший выстрел в том, чтобы стать первоклассным гражданином в моей интерфейсной коммунальной ремне!
- Он приносит в алгебраические типы, варианты, вращения и тип проверки того, что я любил в эльме.
- Это позволяет мне использовать мутацию, где мне это нужно более или менее простым способом.
- Реагистрационная интеграция – это первоклассное рассмотрение (это у парня, который создал реагирование).
- Он быстро компилирует (вроде, в миллисекундах)!
- Проверка ошибок соперников ELM; Это хорошее заседание, и сообщения об ошибках довольно просты.
- Я могу легко вызвать код JS. Это была моя самая большая скоба с эльмом. По причине я чувствую, что The TypeChecker и Ecosystem причина помогает мне избежать ошибок времени выполнения, но дает мне выход, когда мне нужно использовать JS напрямую.
В этой статье я надеюсь, что приведет к вашему аппетиту, создав приложение базовой причины и добавить базовый счетчик.
Сначала установите платформу BescleScript:
$> npm install -g bs-platform $> npx create-react-app reasonableTodo --scripts-version reason-scripts $> cd reasonableTodo $> yarn start
Теперь перейдите к https://localhost: 3000
:
Теперь, когда у нас есть стартер, чтобы построить, давайте посмотрим на то, что на самом деле здесь. Любой, кто знаком с React-Scripts, узнает макет. Самые большие различия будут в /SRC
Отказ Здесь есть два основных файла, которые вы должны заботиться:
index.re
: Это где монтируется дом.App.re
: Корневой компонент.
App.re
Где корня нашего дерева реагирования проживает:
[%bs.raw {|require('./App.css')|}]; [@bs.module] external logo : string = "./logo.svg"; let component = ReasonReact.statelessComponent("App"); let make = (~message, _children) => { ...component, render: _self =>, };(ReasonReact.string(message))
(ReasonReact.string("To get started, edit")) (ReasonReact.string(" src/App.re ")) (ReasonReact.string("and save to reload."))
Давайте рассмотрим эту строку по линии:
[%bs.raw {|require('./App.css')|}];
Современный JavaScript с типичным потоком WebPack – это лабиринтский беспорядок стандартов, которые были бы невозможны полностью поддерживать. Учитывая сумму транспортировщиков, которые могут потребоваться в типичной сборке, было бы невозможно повод для учета всего.
Для таких случаев причина обеспечивает избежать люка Via% Bs.Raw {
Причина предоставляет JS
Интерфейс для доступа к браузерно, хотя и функциональная обертка. Например, Console.log можно получить доступ как js.log ().
[@bs.module] external logo : string = "./logo.svg";
Эта часть новая для меня, но по сути он объявляет «логотип» в качестве подмодуля, который он загружает как строку. Когда я js.log () это, «логотип» печатается как "/static/media/logo.e2342b05.svg"
Отказ Другими словами, он динамически генерирует ссылку URL Build для значка SVG.
let component = ReasonReact.statelessComponent("App");
Обратите внимание, что мы проходим в «приложении» как имя. Причина связывает его так, чтобы его можно было использовать в любом месте, как вы можете глобально включать угловые директивы. Вот почему вы можете напрямую использовать
index.re`
В отличие от реакции в JS, где мы расширяем rage.component, в RUSIONML, вы создаете компонент в качестве основы, из которого мы получим ваш конкретный компонент. В некоторых отношениях очень похоже на продление прототипа вручную, прежде чем классы ES6 стали широко распространены.
//no one writes js like this anymore. var baseObj = {.._methods_go_here_..}; SuperFunc.prototype = Object.extend({}, baseObj); let instance = new SuperFunc();
В этом конкретном случае мы создаем Компонент без гражданства в отличие от гостевого компонента, который мы увидим позже.
let make = (~message, _children) => { ...component ... };
Причина проходит усилия о том, чтобы сделать реквизит супер-пупер явное. сделать Ожидается по системе причина как функция для генерации компонента. Параметры, которые передаются в реквизитах, а дети всегда будут последними. В отличие от JavaScript, ARITY является супер важной и не может быть проигнорирована. Если вы не используете детей, добавьте _ к концу, что предотвращает компилятор о выдаче предупреждений на неиспользуемые переменные. В этом случае ~ сообщение является первым нагрузкой, который также является React Prop и будет roppsmessage
в стандартном реактивный компонент.
Реквисы также могут быть даны нумеры и значения по умолчанию; Мы могли бы просто так легко дать это ~ Сообщение =?
для дополнительного сообщения или ~ Сообщение = "Hello World"
Чтобы дать ему значение по умолчанию.
...component
Подобно ES6-операторам ES6, этот синтаксис здесь делает наш компонент наследует поведение от базового уровня без природы.
...component, render: _self =>,(ReasonReact.string(message))
(ReasonReact.string("To get started, edit")) (ReasonReact.string(" src/App.re ")) (ReasonReact.string("and save to reload."))
В отличие от JavaScript версия реагирования, нет это
Таким образом, для жизненных циклов, причина обеспечивает себя самим собой, что крючки в методах компенсации реагирования. Помимо этого, это должно быть простым, кроме необходимости использовать разумность. Это существует, чтобы включить пуленепробиваемую TypeChecking, которое делает его таким здоровым.
Теперь, когда мы охватывали основы, давайте добавим небольшой счетчик на страницу. В традиционном приложении React мы можем использовать магазин Redux:
const ADD_ACTION = 'ADD_ACTION'; const addAction = () => ({ type: ADD_ACTION }) const reducer = (state=0, action) => { switch (action.type) { case ADD_ACTION: state = state + 1; return state; default: return state; } }
Сама причина полностью делает устаревшее использование redux Имея встроенный компонент состояния, который обернет гораздо чище чистую систему редуктора первого класса в качестве первоклассного гражданина. Чтобы создать элементную компонент, мы используем Разумность.reducerComponent (_Name_)
Отказ
Существует два новых параметра, которые необходимо добавить в функцию MAKE:
- инициация : Функция, которая возвращает исходное состояние, аналогично тому, как она работает в Redux.
- Редуктор Также как редуктор Redux, который принимает состояние и действие; Редуктор возвращает новый объект состояния.
Последнее, но не менее важное, нам нужно создать некоторые действия. Вот где причина действительно сияет. Redux заставляет нас полагаться на сравнительно примитивные инструменты, такие как строковое сравнение. Причина приносит полную мощность Варианты из его ocaml корней. По сути, мы можем опечатать наши действия в скомпилировании!
Определение добавления и вычести становится намного проще и простым. Мы просто заявляем их как варианты типа действия.
/* Counter.re */ type action = | Add | Subtract;
Создание компонента аналогично созданию компонента без вождения, а также две вышеупомянутые параметры. Наш редуктор использует оператор коммутатора аналогично Redux, только мы используем разумное значение .update () для обновления состояния. Это в первую очередь для поддержки асинхронного поведения:
/* Counter.re */ let component = ReasonReact.reducerComponent("Counter"); let make = (_children) => { ...component, initialState: () => 0, /* sets the initial state to 0 */ reducer: (action, state) => switch action { | Add => ReasonReact.Update(state + 1) | Subtract => ReasonReact.Update(state - 1) }, render: (_self) => { let countMessage = "Count: " ++ string_of_int(self.state);}, };(ReasonReact.stringToElement(countMessage))
Последнее, что нам нужно здесь, – это кнопки для фактически отправления этих действий. Вот где _self входит. Функция рендеринга передается Я Аргумент, который дает ему доступ к помощникам компонентов. В этом случае мы можем использовать Self.send, чтобы отправить действие. Используется с обратными вызовами в кнопках, мы можем завершить наш счетчик:
/* Counter.re */ type action = | Add | Subtract; let component = ReasonReact.reducerComponent("Counter"); let make = (_children) => { ...component, initialState: () => 0, reducer: (action, state) => switch action { | Add => ReasonReact.Update(state + 1) | Subtract => ReasonReact.Update(state - 1) }, render: (self) => { let countMessage = "Count: " ++ string_of_int(self.state);}, };(ReasonReact.stringToElement(countMessage))
Чтобы добавить его в наше приложение, просто добавьте
[%bs.raw {|require('./App.css')|}]; [@bs.module] external logo : string = "./logo.svg"; Js.log(logo); let component = ReasonReact.statelessComponent("App"); let make = (~message, _children) => { ...component, render: _self =>, };(ReasonReact.string(message))
(ReasonReact.string("To get started, edit")) (ReasonReact.string(" src/App.re ")) (ReasonReact.string("and save to reload."))
С этим я надеюсь, что вы настроитесь, когда я расширяю это в будущих статьях, когда я строю что-то более существенное!