Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
The missing R in React
Search
Mateusz Zatorski
July 17, 2018
Programming
0
41
The missing R in React
A brief introduction to ReasonML and Reason React
Mateusz Zatorski
July 17, 2018
Tweet
Share
More Decks by Mateusz Zatorski
See All by Mateusz Zatorski
Building mobile apps in React Native using ReasonML
knowbody
2
420
React Router 1.0
knowbody
1
94
Other Decks in Programming
See All in Programming
イベントストーミングから始めるドメイン駆動設計
jgeem
4
800
つよそうにふるまい、つよい成果を出すのなら、つよいのかもしれない
irof
1
270
iOSアプリ開発もLLMで自動運転する
hiragram
6
2.3k
無関心の谷
kanayannet
0
160
Javaに鉄道指向プログラミング (Railway Oriented Pro gramming) のエッセンスを取り入れる/Bringing the Essence of Railway-Oriented Programming to Java
cocet33000
2
530
[初登壇@jAZUG]アプリ開発者が気になるGoogleCloud/Azure+wasm/wasi
asaringo
0
120
Perplexity Slack Botを作ってAI活用を進めた話 / AI Engineering Summit プレイベント
n3xem
0
620
赤裸々に公開。 TSKaigiのオフシーズン
takezoux2
0
110
TypeScript LSP の今までとこれから
quramy
1
480
Cloudflare Realtime と Workers でつくるサーバーレス WebRTC
nekoya3
0
380
統一感のある Go コードを生成 AI の力で手にいれる
otakakot
0
2.9k
プロダクト開発でも使おう 関数のオーバーロード
yoiwamoto
0
140
Featured
See All Featured
Why You Should Never Use an ORM
jnunemaker
PRO
56
9.4k
[RailsConf 2023] Rails as a piece of cake
palkan
55
5.6k
The Language of Interfaces
destraynor
158
25k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Optimising Largest Contentful Paint
csswizardry
37
3.3k
Large-scale JavaScript Application Architecture
addyosmani
512
110k
Become a Pro
speakerdeck
PRO
28
5.4k
The Art of Programming - Codeland 2020
erikaheidi
54
13k
What's in a price? How to price your products and services
michaelherold
245
12k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
10
890
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
26k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
5.8k
Transcript
“The missing R in React” Mateusz Zatorski Twi8er: @matzatorski ⚡
GitHub: @knowbody
react-(R)outer?
react-(R)edux?
react-(R)elay?
(R)
(R)easonML
Why OCaml?
- func<onal - established language - compiled to: bytecode, fast
na<ve or JavaScript - full-featured type system Why OCaml?
Story <me
OCaml compiler OCaml syntax OCaml seman<cs Bytecode Na<ve
js_of_ocaml OCaml syntax OCaml seman<cs Bytecode Na<ve js_of_ocaml
Bloomberg
OCaml syntax OCaml seman<cs Bytecode Na<ve Compiler backend replaced by
BuckleScript OCaml syntax OCaml seman<cs BuckleScript
Facebook
What is ReasonML?
Compiler frontend replaced by Reason Reason syntax OCaml seman<cs Bytecode
Na<ve
Combining everything together Reason syntax OCaml seman<cs BuckleScript
Where we are at today? - syntax familiar to JS
developers - full power of OCaml - clean and readable JS output
Reason CLI
Reason CLI global binaries needed by editor plugins Comes with
a few extra tools: - refmt - “Reason format” - PreQer was inspired by refmt - merlin - engine powering type hint, refactor, real-<me errors, jump to defini<ons, etc. to our editors. - REPL - called rtop, interac<vely evaluates code - re:bench - online benchmarking playground - Redex - the Reason packages registry - ocamlc, ocamlopt, ocamlrun - bare ocaml compilers
Data types
Strings “Hello world” Characters ‘a’ Integers 27 -13 Floats 27.0
-13.0 Integer addiMon 27 + 13 Float addiMon 27.0 +. 13.0 Integer division/mulMplicaMon 14 / 2 * 8 Float division/mulMplicaMon 14.0 /. 2.0 *. 8.0 Float exponenMaMon 3.0 ** 3.0 String concatenaMon “Hello ” ++ “world”
Comparison > < >= <= Boolean operaMons ! && ||
Reference, physical (deep) equality === == Immutable lists [3, 2, 1] Arrays [|1, 2, 3|] Records type person = {age: int}; {age: 18} Comments /* my comment */
Tuple type let coordinates: (float, float) = (48.0, -120.0); let
xCoordinate = getX(coordinates); let yCoordinate = getY(coordinates);
Record type access the individual fields in a record using
the . operator: type person = { name: string, age: int, }; let matt = {name: "Mateusz", age: 12}; matt.name; /* "Mateusz" */ matt.age; /* 12 */
Variant type Enumerated type type shoesColor = | Red |
Blue | Green | Black; type month = | Name(string) | Num(int); let myMonth = Name("February"); let someOtherMonth = Num(3); Union type
Variant type Recursive type type intTree = | Empty /*
atomic */ | Node(int, intTree, intTree); /* compound */
Polymorphic type type list('a) = | Nil | Cons('a, list(‘a));
type stringList = list(string); let myList = Cons("foo", Cons("bar", Cons("baz", Nil))); Singly-linked list “foo” “bar” “baz” Nil
Op<on type type option('a) = | None | Some('a); let
division = (a: int, b: int) : option(int) => if (b === 0) { None; } else { Some(a / b); }; let myLuckyNumber = division(23, 45);
Expressions
let let hardMath = { let x = 4; let
y = x - 1; x + y }; x and y are not accessible outside of hardMath scope let rec factorial = n => if (n === 0) { 1; } else { n * factorial(n - 1); };
if-else let min = (x, y) => if (x <
y) { x; } else { y; };
PaYern matching
if-else let min = (x, y) => if (x <
y) { x; } else { y; }; let min = (x, y) => switch(x < y) { | true => x | false => y };
Func<ons
Labelled arguments let add = (~x, ~y) => {/* use
x and y here */}; add(~y=5, ~x=6);
Currying let add = (x, y) => x + y;
let inc = add(1); inc(10); /* 11 */
Recursive func<ons let rec factorial = n => if (n
=== 0) { 1; } else { n * factorial(n - 1); };
Modules
Modules module Calc = { let add = (x, y)
=> x + y; }; Calc.add(4, 5);
Promises let fetchData = somePromise => somePromise |> Js.Promise.then_(value =>
{ Js.log(value); Js.Promise.resolve(value + 8); }) |> Js.Promise.catch(error => { Js.log("Error!!", error); Js.Promise.resolve(-2); });
JavaScript interop
JavaScript interop let jsCalculate: (array(int), int) => int = [%bs.raw
{| function (numbers, scaleFactor) { var result = 0; numbers.forEach(number => { result += number; }); return result * scaleFactor; } |} ]; let calculate = (numbers, scaleFactor) => jsCalculate(Array.of_list(numbers), scaleFactor); Js.log(calculate([1, 2, 3], 10)); /* -> 60 */
Component
Component let component = ReasonReact.statelessComponent("App"); let make = _children =>
{ ...component, render: _self => <div> <h1> (ReasonReact.string("Welcome!")) </h1> </div>, };
Component let component = ReasonReact.statelessComponent(“App"); let make = (~message, _children)
=> { ...component, render: _self => <div> (ReasonReact.string(message)) </div>, };
Component let component = ReasonReact.statelessComponent("App"); let make = (~fooProp, ~barProp,
_children) => { ...component, /* render and lifecycle methods go here */ };
Stateful component
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
type state = {isEnabled: bool}; type action = | Click;
let component = ReasonReact.reducerComponent("App"); let make = _children => { ...component, initialState: () => {isEnabled: true}, reducer: (action, state) => switch (action) { | Click => ReasonReact.Update({isEnabled: ! state.isEnabled}) }, render: self => <div> <h1 onClick=(_event => self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off")) </h1> </div>, };
Arrays
type person = { name: string, age: int, }; let
people: array(person) = [| {name: "Matt", age: 26}, {name: "Czysty", age: 6}, |]; Arrays
type person = { name: string, age: int, }; let
people: array(person) = [| {name: "Matt", age: 26}, {name: "Czysty", age: 6}, |]; let component = ReasonReact.statelessComponent("App"); let make = _children => { ...component, render: _self => <div> ( ReasonReact.array( Array.map( (person: person) => <p> (ReasonReact.string(person.name)) </p>, people, ), ) ) </div>, };
type person = { name: string, age: int, }; let
people: array(person) = [| {name: "Matt", age: 26}, {name: "Czysty", age: 6}, |]; let component = ReasonReact.statelessComponent("App"); let make = _children => { ...component, render: _self => <div> ( people |> Array.map((person: person) => <p> (ReasonReact.string(person.name)) </p> ) |> ReasonReact.array ) </div>, };
Let’s build something
Install reason-cli npm install -g
[email protected]
Install bs-pla\orm npm install
-g bs-platform Add reason plugin to your editor vscode-reasonml
reason-react bsb -init my-react-app -theme react cd my-react-app && npm
install && npm start # in another tab npm run webpack