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

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.

David Kopal

August 19, 2018
Tweet

More Decks by David Kopal

Other Decks in Programming

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