Use Reason in your React applications

Use Reason in your React applications

Reason is a syntax on top of Ocaml that compiles to JavaScript. Join me, and discover the power of the built-in type system. You’ll learn how to build a React app using Reason as we’ll go through the source code of such app. In doing so, you’ll learn Reason’s core principles as well.

6b50fbb7ade3c6b576b2c2b8ed4b0f7d?s=128

David Kopal

August 19, 2018
Tweet

Transcript

  1. Use ason in your React applications David Kopal

  2. @coding_lawyer 
 @coding_lawyer codinglawyer.net

  3. @coding_lawyer lambdup.io

  4. @coding_lawyer Who heard about ason?

  5. @coding_lawyer

  6. @coding_lawyer Header DisplayList Footer

  7. @coding_lawyer Header DisplayList Footer UI

  8. @coding_lawyer

  9. @coding_lawyer Who wants to write better React?

  10. @coding_lawyer 1. JavaScript has a lot of issues

  11. @coding_lawyer ‣ versatile ‣ dynamic ‣ freedom

  12. @coding_lawyer ‣ no standards ‣ difficult to scale ‣ “this”

    keyword
  13. @coding_lawyer !+[]+[]+![] //"truefalse"

  14. @coding_lawyer 1. JavaScript has a lot of issues a. libraries

    and tools
  15. @coding_lawyer

  16. @coding_lawyer

  17. @coding_lawyer 1. JavaScript has a lot of issues a. libraries

    and tools b. compile to JavaScript
  18. @coding_lawyer

  19. @coding_lawyer

  20. @coding_lawyer JavaScript development is hard

  21. @coding_lawyer 1. JavaScript has a lot of issues a. libraries

    and tools b. compile to JavaScript 2. React isn’t a native JavaScript library
  22. @coding_lawyer React is based on different principles

  23. @coding_lawyer Immutability Type system Functional programming

  24. @coding_lawyer Immutability Type system Functional programming

  25. @coding_lawyer

  26. @coding_lawyer

  27. @coding_lawyer familiar syntax

  28. @coding_lawyer semantics familiar syntax

  29. @coding_lawyer let fizzbuzz = (i) => switch (i mod 3,

    i mod 5) { | (0, 0) => "FizzBuzz" | (0, _) => "Fizz" | (_, 0) => "Buzz" | _ => string_of_int(i) }; for (i in 1 to 100) { Js.log(fizzbuzz(i)) };
  30. @coding_lawyer compiler

  31. @coding_lawyer function fizzbuzz(i) { var match = i % 3

    var match$1 = i % 5 if (match !== 0) { if (match$1 !== 0) { return String(i) } else { return 'Buzz' } } else if (match$1 !== 0) { return 'Fizz' } else { return 'FizzBuzz' } } for (var i = 1; i <= 100; ++i) { console.log(fizzbuzz(i)) } let fizzbuzz = (i) => switch (i mod 3, i mod 5) { | (0, 0) => "FizzBuzz" | (0, _) => "Fizz" | (_, 0) => "Buzz" | _ => string_of_int(i) }; for (i in 1 to 100) { Js.log(fizzbuzz(i)) };
  32. @coding_lawyer JavaScript interop

  33. @coding_lawyer c Native code (ocamlopt) Bytecode (ocamlc) JavaScript (bsc) c

  34. @coding_lawyer github.com/jaredly/gravitron

  35. @coding_lawyer Reason is compatible with React React was developed for

    Reason
  36. @coding_lawyer adjusted JavaScript to React’s needs

  37. @coding_lawyer

  38. @coding_lawyer

  39. @coding_lawyer

  40. @coding_lawyer semantics familiar syntax

  41. @coding_lawyer statically typed cousin of JavaScript

  42. @coding_lawyer safer React

  43. @coding_lawyer JavaScript-like syntax React friendly

  44. @coding_lawyer “[Reason] is the best way to take React to

    the next level” Jordan Walke, creator of Reason, React
  45. @coding_lawyer Tic Tac Toe github.com/codinglawyer/reason-tic-tac-toe

  46. @coding_lawyer

  47. @coding_lawyer

  48. @coding_lawyer

  49. @coding_lawyer

  50. @coding_lawyer Game Board App BoardRow Square SharedTypes CSS

  51. @coding_lawyer Game Board App BoardRow Square SharedTypes CSS

  52. @coding_lawyer Game Board App BoardRow Square SharedTypes CSS

  53. @coding_lawyer Game Board App BoardRow Square SharedTypes CSS

  54. @coding_lawyer Game Board App BoardRow Square SharedTypes CSS

  55. @coding_lawyer Game Board App BoardRow Square SharedTypes CSS

  56. @coding_lawyer Game Board App BoardRow Square SharedTypes CSS

  57. @coding_lawyer type system

  58. @coding_lawyer clearer and safer code

  59. @coding_lawyer superior to Flow and TypeScript

  60. @coding_lawyer type inference

  61. @coding_lawyer type player = | Cross | Circle; type field

    = | Empty | Marked(player); type row = list(field) type board = list(row); type gameState = | Playing(player) | Winner(player) | Draw; type state = { board, gameState, };
  62. @coding_lawyer State let initialState = { board: [ [Empty, Empty,

    Empty], [Empty, Empty, Empty], [Empty, Empty, Empty], ], gameState: Playing(Cross), };
  63. @coding_lawyer it takes some time to learn static typing

  64. @coding_lawyer

  65. @coding_lawyer components

  66. @coding_lawyer stateless component

  67. @coding_lawyer Game Board App BoardRow Square SharedTypes CSS

  68. @coding_lawyer let component = ReasonReact.statelessComponent("App"); let make = _children =>

    { ...component, render: _self => <div> <div className=“title"> (ReasonReact.string("Tic Tac Toe")) </div> <Game /> </div>, };
  69. @coding_lawyer

  70. @coding_lawyer reducer component

  71. @coding_lawyer Game Board App BoardRow Square SharedTypes CSS

  72. @coding_lawyer let component = ReasonReact.reducerComponent("Game"); let make = _children =>

    { ...component, initialState: () => initialState, reducer: (action: action, state: state) => switch (action) { | Restart => … | ClickSquare((id: string)) => … }, render: ({state, send}) => <div className="game"> <Board state onRestart=(_evt => send(Restart)) onMark=(id => send(ClickSquare(id))) /> </div>, };
  73. @coding_lawyer State let initialState = { board: [ [Empty, Empty,

    Empty], [Empty, Empty, Empty], [Empty, Empty, Empty], ], gameState: Playing(Cross), };
  74. @coding_lawyer let component = ReasonReact.reducerComponent("Game"); let make = _children =>

    { ...component, initialState: () => initialState, reducer: (action: action, state: state) => switch (action) { | Restart => … | ClickSquare((id: string)) => … }, render: ({state, send}) => <div className="game"> <Board state onRestart=(_evt => send(Restart)) onMark=(id => send(ClickSquare(id))) /> </div>, };
  75. @coding_lawyer let component = ReasonReact.reducerComponent("Game"); let make = _children =>

    { ...component, initialState: () => initialState, reducer: (action: action, state: state) => switch (action) { | Restart => … | ClickSquare((id: string)) => … }, render: ({state, send}) => <div className="game"> <Board state onRestart=(_evt => send(Restart)) onMark=(id => send(ClickSquare(id))) /> </div>, };
  76. @coding_lawyer reducer: (action: action, state: state) => switch (action) {

    | Restart => ReasonReact.Update(initialState) | ClickSquare((id: string)) => let updatedBoard = updateBoard( state.board, state.gameState, id); let updatedGs = checkGameState3x3( updatedBoard, state.board, state.gameState); ReasonReact.Update({ board: updatedBoard, gameState: updatedGs, }); },
  77. @coding_lawyer reducer: (action: action, state: state) => switch (action) {

    | Restart => ReasonReact.Update(initialState) | ClickSquare((id: string)) => let updatedBoard = updateBoard( state.board, state.gameState, id); let updatedGs = checkGameState3x3( updatedBoard, state.board, state.gameState); ReasonReact.UpdateWithSideEffects( { board: updatedBoard, gameState: updatedGs, }, (_self => Js.log(“Clicked")), ); },
  78. @coding_lawyer pure state update and side-effects separation

  79. @coding_lawyer less boilerplate

  80. @coding_lawyer Redux’s principles and component’s reusability

  81. @coding_lawyer pattern matching

  82. @coding_lawyer reducer: (action: action, state: state) => switch (action) {

    | Restart => ReasonReact.Update(initialState) | ClickSquare((id: string)) => let updatedBoard = updateBoard( state.board, state.gameState, id); let updatedGs = checkGameState3x3( updatedBoard, state.board, state.gameState); ReasonReact.Update({ board: updatedBoard, gameState: updatedGs, }); },
  83. @coding_lawyer let updateBoard = (board: board, gameState: gameState, id) =>

    board |> List.mapi((ind: int, row: row) => row |> List.mapi((index: int, value: field) => string_of_int(ind) ++ string_of_int(index) === id ? switch (gameState, value) { | (_, Marked(_)) => value | (Playing(player), Empty) => Marked(player) | (_, Empty) => Empty } : value ) );
  84. @coding_lawyer let updateBoard = (board: board, gameState: gameState, id) =>

    board |> List.mapi((ind: int, row: row) => row |> List.mapi((index: int, value: field) => string_of_int(ind) ++ string_of_int(index) === id ? switch (gameState, value) { | (_, Marked(_)) => value | (Playing(player), Empty) => Marked(player) | (_, Empty) => Empty } : value ) );
  85. @coding_lawyer type field = | Empty | Marked(player); type gameState

    = | Playing(player) | Winner(player) | Draw;
  86. @coding_lawyer switch (gameState: gameState, value: field) { | (_, Marked(_))

    => value | (Playing(player), Empty) => Marked(player) | (_, Empty) => Empty }
  87. @coding_lawyer

  88. @coding_lawyer switch ( getWinner(flattenBoard, head), gameEnded(flattenBoard), tail, ) { |

    (Cross, _, _) => Winner(Cross) | (Circle, _, _) => Winner(Circle) | (_, true, []) => Draw | (_, false, []) => whosPlaying(gameState) | _ => check(tail) };
  89. @coding_lawyer switch (match$1) { case 0 : return /* Winner

    */Block.__(1, [/* Cross */0]); case 1 : return /* Winner */Block.__(1, [/* Circle */1]); case 2 : if (match$2) { if (tail) { _rest = tail; continue ; } else { return /* Draw */0; } } else if (tail) { _rest = tail; continue ; } else { return whosPlaying(gameState); } }
  90. @coding_lawyer Labelled arguments

  91. @coding_lawyer let createPlayingBoard = (~width: int, ~height: int) => Array.make_matrix(width,

    height, "Field"); createPlayingBoard(~width=100, ~height=50);
  92. @coding_lawyer Game Board App BoardRow Square SharedTypes CSS

  93. @coding_lawyer let component = ReasonReact.statelessComponent("Board"); let make = (~state: state,

    ~onMark, ~onRestart, _children) => { ...component, render: _ => <div className="game-board"> ( ReasonReact.array( Array.of_list( List.mapi( (index: int, row: row) => <BoardRow key=(string_of_int(index)) gameState=state.gameState row onMark index />, state.board, ),), )) /* ... */ </div>,};
  94. @coding_lawyer let component = ReasonReact.statelessComponent("Board"); let make = (~state: state,

    ~onMark, ~onRestart, _children) => { ...component, render: _ => <div className="game-board"> ( ReasonReact.array( Array.of_list( List.mapi( (index: int, row: row) => <BoardRow key=(string_of_int(index)) gameState=state.gameState row onMark index />, state.board, ),), )) /* ... */ </div>,};
  95. @coding_lawyer let component = ReasonReact.reducerComponent("Game"); let make = _children =>

    { ...component, initialState: () => initialState, reducer: (action: action, state: state) => switch (action) { | Restart => … | ClickSquare((id: string)) => … }, render: ({state, send}) => <div className="game"> <Board state onRestart=(_evt => send(Restart)) onMark=(id => send(ClickSquare(id))) /> </div>, };
  96. @coding_lawyer List

  97. @coding_lawyer list array

  98. @coding_lawyer let numbers = [1, 5, 8, 9, 15]; let

    increasedNumbers = List.map((num) => num + 2, numbers); Js.log(increasedNumbers); /* [3,[7,[10,[11,[17,0]]]]] */
  99. @coding_lawyer let numbers = [1, 5, 8, 9, 15]; let

    increasedNumbers = List.map((num) => num + 2, numbers); Js.log(increasedNumbers); /* [3,[7,[10,[11,[17,0]]]]] */ Js.log(Array.of_list(increasedNumbers)); /* [3,7,10,11,17] */
  100. @coding_lawyer State let initialState = { board: [ [Empty, Empty,

    Empty], [Empty, Empty, Empty], [Empty, Empty, Empty], ], gameState: Playing(Cross), };
  101. @coding_lawyer let component = ReasonReact.statelessComponent("Board"); let make = (~state: state,

    ~onMark, ~onRestart, _children) => { ...component, render: _ => <div className="game-board"> ( ReasonReact.array( Array.of_list( List.mapi( (index: int, row: row) => <BoardRow key=(string_of_int(index)) gameState=state.gameState row onMark index />, state.board, ),), )) /* ... */ </div>,};
  102. @coding_lawyer let component = ReasonReact.statelessComponent("Board"); let make = (~state: state,

    ~onMark, ~onRestart, _children) => { ...component, render: _ => <div className="game-board"> ( ReasonReact.array( Array.of_list( List.mapi( (index: int, row: row) => <BoardRow key=(string_of_int(index)) gameState=state.gameState row onMark index />, state.board, ),), )) /* ... */ </div>,};
  103. @coding_lawyer let component = ReasonReact.statelessComponent("Board"); let make = (~state: state,

    ~onMark, ~onRestart, _children) => { ...component, render: _ => <div className="game-board"> ( state.board |> List.mapi((index: int, row: row) => <BoardRow key=(string_of_int(index)) gameState=state.gameState row onMark index /> ) |> Array.of_list |> ReasonReact.array )) /* ... */ </div>,};
  104. @coding_lawyer Why should you use React in Reason?

  105. @coding_lawyer Reason is compatible with React's principles

  106. @coding_lawyer strong type system

  107. @coding_lawyer pattern matching

  108. @coding_lawyer functional programming features

  109. @coding_lawyer stateless and stateful component separation

  110. @coding_lawyer Get your hands dirty!

  111. @coding_lawyer 
 codinglawyer.net @coding_lawyer

  112. @coding_lawyer Questions?

  113. @coding_lawyer Thank You

  114. @coding_lawyer @coding_lawyer codinglawyer.net github.com/codinglawyer/reason-tic-tac-toe