Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building mobile apps in React Native using ReasonML

Building mobile apps in React Native using ReasonML

These are my slides from the LambdUp 2018 conference in Prague. https://www.lambdup.io/

Mateusz Zatorski

September 13, 2018
Tweet

More Decks by Mateusz Zatorski

Other Decks in Technology

Transcript

  1. - func0onal - established language - compiled to: bytecode, fast

    na0ve or JavaScript - full-featured type system Why OCaml?
  2. OCaml syntax OCaml seman0cs Bytecode Na0ve Compiler backend replaced by

    BuckleScript OCaml syntax OCaml seman0cs BuckleScript
  3. Where we are today? - syntax familiar to JS developers

    - full power of OCaml - clean and readable JS output
  4. 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
  5. 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”
  6. 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 */
  7. Tuple type let coordinates: (float, float) = (48.0, -120.0); let

    xCoordinate = getX(coordinates); let yCoordinate = getY(coordinates);
  8. 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 */
  9. 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);
  10. Variant type Variant as self-recursive data structure type intTree =

    | Empty /* atomic */ | Node(int, intTree, intTree); /* compound */
  11. 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
  12. 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);
  13. 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); };
  14. if-else let min = (x, y) => if (x <

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

    y) { x; } else { y; }; let min = (x, y) => switch(x < y) { | true => x | false => y };
  16. Labelled arguments let add = (~x, ~y) => {/* use

    x and y here */}; add(~y=5, ~x=6);
  17. 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;
  18. Recursive func0ons let rec factorial = n => if (n

    === 0) { 1; } else { n * factorial(n - 1); };
  19. Modules module Calc = { let add = (x, y)

    => x + y; }; Calc.add(4, 5);
  20. 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 */
  21. Component let component = ReasonReact.statelessComponent("App"); let make = _children =>

    { ...component, render: _self => <div> <h1> (ReasonReact.string("Welcome!")) </h1> </div>, };
  22. Component let component = ReasonReact.statelessComponent(“App"); let make = (~message, _children)

    => { ...component, render: _self => <div> (ReasonReact.string(message)) </div>, };
  23. Component let component = ReasonReact.statelessComponent("App"); let make = (~fooProp, ~barProp,

    _children) => { ...component, /* render and lifecycle methods go here */ };
  24. 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>, };
  25. 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>, };
  26. 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>, };
  27. 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>, };
  28. 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>, };
  29. 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>, };
  30. 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>, };
  31. 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>, };
  32. type person = { name: string, age: int, }; let

    people: array(person) = [| {name: "Matt", age: 26}, {name: "Czysty", age: 6}, |]; Arrays
  33. 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>, };
  34. 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>, };
  35. 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
  36. Modify index.js import { app } from './src/App'; import React

    from 'react'; import { AppRegistry } from 'react-native'; AppRegistry.registerComponent('MyReasonApp', () => app);
  37. 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 = () => <View style=styles##container> <Text style=styles##text> (ReasonReact.string("Let's get this party started! " ++ {js||js})) </Text> </View>;