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. 17.
  2. 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
  3. 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)) };
  4. 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)) };
  5. 44.

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

    the next level” Jordan Walke, creator of Reason, React
  6. 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, };
  7. 62.

    @coding_lawyer State let initialState = { board: [ [Empty, Empty,

    Empty], [Empty, Empty, Empty], [Empty, Empty, Empty], ], gameState: Playing(Cross), };
  8. 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>, };
  9. 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>, };
  10. 73.

    @coding_lawyer State let initialState = { board: [ [Empty, Empty,

    Empty], [Empty, Empty, Empty], [Empty, Empty, Empty], ], gameState: Playing(Cross), };
  11. 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>, };
  12. 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>, };
  13. 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, }); },
  14. 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")), ); },
  15. 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, }); },
  16. 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 ) );
  17. 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 ) );
  18. 85.

    @coding_lawyer type field = | Empty | Marked(player); type gameState

    = | Playing(player) | Winner(player) | Draw;
  19. 86.

    @coding_lawyer switch (gameState: gameState, value: field) { | (_, Marked(_))

    => value | (Playing(player), Empty) => Marked(player) | (_, Empty) => Empty }
  20. 88.

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

    (Cross, _, _) => Winner(Cross) | (Circle, _, _) => Winner(Circle) | (_, true, []) => Draw | (_, false, []) => whosPlaying(gameState) | _ => check(tail) };
  21. 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); } }
  22. 91.

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

    height, "Field"); createPlayingBoard(~width=100, ~height=50);
  23. 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>,};
  24. 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>,};
  25. 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>, };
  26. 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]]]]] */
  27. 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] */
  28. 100.

    @coding_lawyer State let initialState = { board: [ [Empty, Empty,

    Empty], [Empty, Empty, Empty], [Empty, Empty, Empty], ], gameState: Playing(Cross), };
  29. 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>,};
  30. 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>,};
  31. 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>,};