Slide 1

Slide 1 text

Building mobile apps in React Na4ve using ReasonML

Slide 2

Slide 2 text

Mateusz Zatorski Twi>er: @matzatorski GitHub: @knowbody

Slide 3

Slide 3 text

Story

Slide 4

Slide 4 text

Story Introduc4on to ReasonML

Slide 5

Slide 5 text

Story Introduc4on to ReasonML DEMO

Slide 6

Slide 6 text

Story Introduc4on to ReasonML DEMO

Slide 7

Slide 7 text

Why OCaml?

Slide 8

Slide 8 text

- func0onal - established language - compiled to: bytecode, fast na0ve or JavaScript - full-featured type system Why OCaml?

Slide 9

Slide 9 text

OCaml compiler OCaml syntax OCaml seman0cs Bytecode Na0ve

Slide 10

Slide 10 text

js_of_ocaml OCaml syntax OCaml seman0cs Bytecode Na0ve js_of_ocaml

Slide 11

Slide 11 text

Bloomberg

Slide 12

Slide 12 text

OCaml syntax OCaml seman0cs Bytecode Na0ve Compiler backend replaced by BuckleScript OCaml syntax OCaml seman0cs BuckleScript

Slide 13

Slide 13 text

Facebook

Slide 14

Slide 14 text

What is ReasonML?

Slide 15

Slide 15 text

Compiler frontend replaced by Reason Reason syntax OCaml seman0cs Bytecode Na0ve

Slide 16

Slide 16 text

Combining everything together Reason syntax OCaml seman0cs BuckleScript

Slide 17

Slide 17 text

Where we are today? - syntax familiar to JS developers - full power of OCaml - clean and readable JS output

Slide 18

Slide 18 text

Reason CLI

Slide 19

Slide 19 text

Reason CLI global binaries needed by editor plugins Comes with a few extra tools: - refmt - “Reason format” - PreOer was inspired by refmt - merlin - engine powering type hint, refactor, 
 real-0me errors, jump to defini0ons, etc. 
 to our editors. - REPL - called rtop, interac0vely evaluates code - re:bench - online benchmarking playground - Redex - the Reason packages registry - ocamlc, ocamlopt, ocamlrun - bare ocaml compilers

Slide 20

Slide 20 text

Data types

Slide 21

Slide 21 text

Strings “Hello world” Characters ‘a’ Integers 27 -13 Floats 27.0 -13.0 Integer addi4on 27 + 13 Float addi4on 27.0 +. 13.0 Integer division/mul4plica4on 14 / 2 * 8 Float division/mul4plica4on 14.0 /. 2.0 *. 8.0 Float exponen4a4on 3.0 ** 3.0 String concatena4on “Hello ” ++ “world”

Slide 22

Slide 22 text

Comparison > < >= <= Boolean opera4ons ! && || Reference, physical (deep) equality === == Immutable lists [3, 2, 1] Arrays [|1, 2, 3|] Records type person = {age: int}; {age: 18} Comments /* my comment */

Slide 23

Slide 23 text

Tuple type let coordinates: (float, float) = (48.0, -120.0); let xCoordinate = getX(coordinates); let yCoordinate = getY(coordinates);

Slide 24

Slide 24 text

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 */

Slide 25

Slide 25 text

Variant type Variant as set of symbols (enum) type shoesColor = | Red | Blue | Green | Black; Variant as data structure type point = | Point(float, float); type shape = | Rectangle(point, point) | Circle(point, float);

Slide 26

Slide 26 text

Variant type Variant as self-recursive data structure type intTree = | Empty /* atomic */ | Node(int, intTree, intTree); /* compound */

Slide 27

Slide 27 text

Polymorphic type type list('a) = | Nil | Cons('a, list(‘a)); let myList = Cons("foo", Cons("bar", Cons("baz", Nil))); Singly-linked list “foo” “bar” “baz” Nil

Slide 28

Slide 28 text

Op0on 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);

Slide 29

Slide 29 text

Expressions

Slide 30

Slide 30 text

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); };

Slide 31

Slide 31 text

if-else let min = (x, y) => if (x < y) { x; } else { y; };

Slide 32

Slide 32 text

PaXern matching

Slide 33

Slide 33 text

if-else let min = (x, y) => if (x < y) { x; } else { y; }; let min = (x, y) => switch(x < y) { | true => x | false => y };

Slide 34

Slide 34 text

Func0ons

Slide 35

Slide 35 text

Labelled arguments let add = (~x, ~y) => {/* use x and y here */}; add(~y=5, ~x=6);

Slide 36

Slide 36 text

Currying let add = (x, y) => x + y; let inc = add(1); inc(10); /* 11 */ let add = (a, b) => a + b; let alsoAdd = a => b => a + b;

Slide 37

Slide 37 text

Recursive func0ons let rec factorial = n => if (n === 0) { 1; } else { n * factorial(n - 1); };

Slide 38

Slide 38 text

Modules

Slide 39

Slide 39 text

Modules module Calc = { let add = (x, y) => x + y; }; Calc.add(4, 5);

Slide 40

Slide 40 text

JavaScript interop

Slide 41

Slide 41 text

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 */

Slide 42

Slide 42 text

Component

Slide 43

Slide 43 text

Component let component = ReasonReact.statelessComponent("App"); let make = _children => { ...component, render: _self =>

(ReasonReact.string("Welcome!"))

, };

Slide 44

Slide 44 text

Component let component = ReasonReact.statelessComponent(“App"); let make = (~message, _children) => { ...component, render: _self =>
(ReasonReact.string(message))
, };

Slide 45

Slide 45 text

Component let component = ReasonReact.statelessComponent("App"); let make = (~fooProp, ~barProp, _children) => { ...component, /* render and lifecycle methods go here */ };

Slide 46

Slide 46 text

Stateful component

Slide 47

Slide 47 text

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 =>

self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off"))

, };

Slide 48

Slide 48 text

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 =>

self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off"))

, };

Slide 49

Slide 49 text

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 =>

self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off"))

, };

Slide 50

Slide 50 text

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 =>

self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off"))

, };

Slide 51

Slide 51 text

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 =>

self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off"))

, };

Slide 52

Slide 52 text

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 =>

self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off"))

, };

Slide 53

Slide 53 text

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 =>

self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off"))

, };

Slide 54

Slide 54 text

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 =>

self.send(Click))> (ReasonReact.string(self.state.isEnabled ? "on" : "off"))

, };

Slide 55

Slide 55 text

Arrays

Slide 56

Slide 56 text

type person = { name: string, age: int, }; let people: array(person) = [| {name: "Matt", age: 26}, {name: "Czysty", age: 6}, |]; Arrays

Slide 57

Slide 57 text

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 =>
( ReasonReact.array( Array.map( (person: person) =>

(ReasonReact.string(person.name))

, people, ), ) )
, };

Slide 58

Slide 58 text

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 =>
( people |> Array.map((person: person) =>

(ReasonReact.string(person.name))

) |> ReasonReact.array )
, };

Slide 59

Slide 59 text

Let’s build something

Slide 60

Slide 60 text

Adding ReasonML to React Na0ve project yarn add bs-platform reason-react bs-react-native

Slide 61

Slide 61 text

touch bsconfig.json { "name": "my-reason-react-native-app", "reason": { "react-jsx": 2 }, "bsc-flags": ["-bs-super-errors"], "bs-dependencies": ["bs-react-native", "reason-react"], "sources": [ { "dir": "src" } ], "package-specs": { "module": "commonjs", "in-source": true }, "refmt": 3 } Add bsconfig.json

Slide 62

Slide 62 text

Modify index.js import { app } from './src/App'; import React from 'react'; import { AppRegistry } from 'react-native'; AppRegistry.registerComponent('MyReasonApp', () => app);

Slide 63

Slide 63 text

Let’s add our first component src/App.re open BsReactNative; let styles = StyleSheet.create( Style.( { "container": style([flex(1.), justifyContent(Center), alignItems(Center)]), "text": style([fontSize(Float(26.))]), } ), ); let app = () => (ReasonReact.string("Let's get this party started! " ++ {js||js})) ;