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
38
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
310
React Router 1.0
knowbody
1
91
Other Decks in Programming
See All in Programming
Fragment Composition of GraphQL
quramy
13
1.5k
サイコロで理解する統計的仮説検定の考え方
tatamiya
4
1k
AWS CDKコントリビュートTIPS / aws-cdk-contribution-tips
gotok365
4
390
ServerAction で Progressive Enhancement はどこまで頑張れるか? / progressive-enhancement-with-server-action
takefumiyoshii
6
430
Introducing Kotlin Multiplatform in an existing mobile app - Workshop Edition | AndroidMakers Paris
prof18
0
150
大規模UIKitベースアプリへのTCAの段階的導入/gradual-adoption-of-tca-in-a-large-scale-uikit-based-app
takehilo
2
210
Hanami and htmx
bkuhlmann
0
220
TCAとKMPを用いた新規動画配信アプリ 「ABEMA Live」の設計
tomu28
2
130
Elm Form Validation
bkuhlmann
0
510
FigmaとPHPで作る1ミリたりとも表示崩れしない最強の帳票印刷ソリューション
ttskch
43
19k
Try creating your own orderedmap
kazamori
1
210
Goのエラースタックトレースの歴史と今後
sonatard
10
1.8k
Featured
See All Featured
How to train your dragon (web standard)
notwaldorf
75
5.2k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
221
21k
The World Runs on Bad Software
bkeepers
PRO
61
6.7k
Embracing the Ebb and Flow
colly
80
4.2k
Building an army of robots
kneath
300
41k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
323
20k
Thoughts on Productivity
jonyablonski
60
3.9k
Infographics Made Easy
chrislema
238
18k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
228
16k
The Invisible Customer
myddelton
114
12k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
358
22k
The Brand Is Dead. Long Live the Brand.
mthomps
49
29k
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