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. @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
  2. @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)) };
  3. @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)) };
  4. @coding_lawyer “[Reason] is the best way to take React to

    the next level” Jordan Walke, creator of Reason, React
  5. @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, };
  6. @coding_lawyer State let initialState = { board: [ [Empty, Empty,

    Empty], [Empty, Empty, Empty], [Empty, Empty, Empty], ], gameState: Playing(Cross), };
  7. @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>, };
  8. @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>, };
  9. @coding_lawyer State let initialState = { board: [ [Empty, Empty,

    Empty], [Empty, Empty, Empty], [Empty, Empty, Empty], ], gameState: Playing(Cross), };
  10. @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>, };
  11. @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. @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, }); },
  13. @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")), ); },
  14. @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, }); },
  15. @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 ) );
  16. @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. @coding_lawyer type field = | Empty | Marked(player); type gameState

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

    => value | (Playing(player), Empty) => Marked(player) | (_, Empty) => Empty }
  19. @coding_lawyer switch ( getWinner(flattenBoard, head), gameEnded(flattenBoard), tail, ) { |

    (Cross, _, _) => Winner(Cross) | (Circle, _, _) => Winner(Circle) | (_, true, []) => Draw | (_, false, []) => whosPlaying(gameState) | _ => check(tail) };
  20. @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); } }
  21. @coding_lawyer let createPlayingBoard = (~width: int, ~height: int) => Array.make_matrix(width,

    height, "Field"); createPlayingBoard(~width=100, ~height=50);
  22. @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>,};
  23. @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. @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>, };
  25. @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]]]]] */
  26. @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] */
  27. @coding_lawyer State let initialState = { board: [ [Empty, Empty,

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