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

Use ReasonML in your React applications (RuhrJS 2018)

Use ReasonML in your React applications (RuhrJS 2018)

David Kopal

October 14, 2018
Tweet

More Decks by David Kopal

Other Decks in Programming

Transcript

  1. ÷÷÷÷÷÷≥≥≥
    Use ReasonML in your
    React applications
    David Kopal

    View Slide

  2. @coding_lawyer
    @coding_lawyer
    codinglawyer.io
    meetup organizer
    contributor
    I’m David Kopal

    View Slide

  3. @coding_lawyer

    View Slide

  4. @coding_lawyer
    Who heard about ason?

    View Slide

  5. @coding_lawyer

    View Slide

  6. @coding_lawyer
    Who wants to write better
    React?

    View Slide

  7. @coding_lawyer
    React isn’t a native JavaScript library

    View Slide

  8. @coding_lawyer

    View Slide

  9. @coding_lawyer
    Immutability

    View Slide

  10. @coding_lawyer
    Immutability

    View Slide

  11. @coding_lawyer
    Immutability

    View Slide

  12. @coding_lawyer
    Immutability
    Functional
    programming

    View Slide

  13. @coding_lawyer
    Immutability
    Functional
    programming

    View Slide

  14. @coding_lawyer
    Immutability
    Functional
    programming

    View Slide

  15. @coding_lawyer
    Immutability
    Type system
    Functional
    programming

    View Slide

  16. @coding_lawyer
    Immutability
    Type system
    Functional
    programming

    View Slide

  17. @coding_lawyer
    Immutability
    Type system
    Functional
    programming

    View Slide

  18. @coding_lawyer
    Immutability
    Type system
    Functional
    programming

    View Slide

  19. @coding_lawyer
    Immutability
    Type system
    Functional
    programming

    View Slide

  20. @coding_lawyer
    Immutability
    Type system
    Functional
    programming

    View Slide

  21. @coding_lawyer
    Immutability
    Type system
    Functional
    programming

    View Slide

  22. @coding_lawyer

    View Slide

  23. @coding_lawyer
    semantics
    familiar syntax

    View Slide

  24. @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))
    };

    View Slide

  25. @coding_lawyer
    compiler

    View Slide

  26. @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))
    };

    View Slide

  27. @coding_lawyer
    JavaScript interop

    View Slide

  28. @coding_lawyer

    View Slide

  29. @coding_lawyer
    Reason is compatible with React

    View Slide

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

    View Slide

  31. @coding_lawyer
    adjusted JavaScript to React’s needs

    View Slide

  32. @coding_lawyer

    View Slide

  33. @coding_lawyer

    View Slide

  34. @coding_lawyer

    View Slide

  35. @coding_lawyer

    View Slide

  36. @coding_lawyer

    View Slide

  37. @coding_lawyer

    View Slide

  38. @coding_lawyer

    View Slide

  39. @coding_lawyer

    View Slide

  40. @coding_lawyer
    semantics
    familiar syntax

    View Slide

  41. @coding_lawyer
    safer React

    View Slide

  42. @coding_lawyer
    “[Reason] is the best way to take
    React to the next level”
    Jordan Walke, creator of Reason, React

    View Slide

  43. @coding_lawyer
    Tic Tac Toe
    github.com/codinglawyer/reason-tic-tac-toe

    View Slide

  44. @coding_lawyer

    View Slide

  45. @coding_lawyer

    View Slide

  46. @coding_lawyer

    View Slide

  47. @coding_lawyer

    View Slide

  48. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  49. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  50. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  51. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  52. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  53. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  54. @coding_lawyer
    components

    View Slide

  55. @coding_lawyer
    stateless component

    View Slide

  56. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  57. @coding_lawyer
    let component = ReasonReact.statelessComponent("App");
    let make = _children => {
    ...component,
    render: _self =>


    (ReasonReact.string("Tic Tac Toe"))


    ,
    };

    View Slide

  58. @coding_lawyer
    let component = ReasonReact.statelessComponent("App");
    let make = _children => {
    ...component,
    render: _self =>


    (ReasonReact.string("Tic Tac Toe"))


    ,
    };

    View Slide

  59. @coding_lawyer
    let component = ReasonReact.statelessComponent("App");
    let make = _children => {
    ...component,
    render: _self =>


    (ReasonReact.string("Tic Tac Toe"))


    ,
    };

    View Slide

  60. @coding_lawyer
    let component = ReasonReact.statelessComponent("App");
    let make = _children => {
    ...component,
    render: _self =>


    (ReasonReact.string("Tic Tac Toe"))


    ,
    };

    View Slide

  61. @coding_lawyer
    let component = ReasonReact.statelessComponent("App");
    let make = _children => {
    ...component,
    render: _self =>


    (ReasonReact.string("Tic Tac Toe"))


    ,
    };

    View Slide

  62. @coding_lawyer
    reducer component

    View Slide

  63. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  64. @coding_lawyer
    let component = ReasonReact.reducerComponent("Game");
    let make = _children => {
    ...component,
    initialState: () => { board: […], gameState:… },
    reducer: (action: action, state: state) =>
    switch (action) {
    | Restart => …
    | ClickSquare((id: string)) => …
    },
    render: ({state, send}) =>

    state
    onRestart=(_evt => send(Restart))
    onMark=(id => send(ClickSquare(id)))
    />
    ,
    };

    View Slide

  65. @coding_lawyer
    let component = ReasonReact.reducerComponent("Game");
    let make = _children => {
    ...component,
    initialState: () => { board: […], gameState:… },
    reducer: (action: action, state: state) =>
    switch (action) {
    | Restart => …
    | ClickSquare((id: string)) => …
    },
    render: ({state, send}) =>

    state
    onRestart=(_evt => send(Restart))
    onMark=(id => send(ClickSquare(id)))
    />
    ,
    };

    View Slide

  66. @coding_lawyer
    let component = ReasonReact.reducerComponent("Game");
    let make = _children => {
    ...component,
    initialState: () => { board: […], gameState:… },
    reducer: (action: action, state: state) =>
    switch (action) {
    | Restart => …
    | ClickSquare((id: string)) => …
    },
    render: ({state, send}) =>

    state
    onRestart=(_evt => send(Restart))
    onMark=(id => send(ClickSquare(id)))
    />
    ,
    };

    View Slide

  67. @coding_lawyer
    let component = ReasonReact.reducerComponent("Game");
    let make = _children => {
    ...component,
    initialState: () => { board: […], gameState:… },
    reducer: (action: action, state: state) =>
    switch (action) {
    | Restart => …
    | ClickSquare((id: string)) => …
    },
    render: ({state, send}) =>

    state
    onRestart=(_evt => send(Restart))
    onMark=(id => send(ClickSquare(id)))
    />
    ,
    };

    View Slide

  68. @coding_lawyer
    let component = ReasonReact.reducerComponent("Game");
    let make = _children => {
    ...component,
    initialState: () => { board: […], gameState:… },
    reducer: (action: action, state: state) =>
    switch (action) {
    | Restart => …
    | ClickSquare((id: string)) => …
    },
    render: ({state, send}) =>

    state
    onRestart=(_evt => send(Restart))
    onMark=(id => send(ClickSquare(id)))
    />
    ,
    };

    View Slide

  69. @coding_lawyer
    let component = ReasonReact.reducerComponent("Game");
    let make = _children => {
    ...component,
    initialState: () => { board: […], gameState:… },
    reducer: (action: action, state: state) =>
    switch (action) {
    | Restart => …
    | ClickSquare((id: string)) => …
    },
    render: ({state, send}) =>

    state
    onRestart=(_evt => send(Restart))
    onMark=(id => send(ClickSquare(id)))
    />
    ,
    };

    View Slide

  70. @coding_lawyer
    let component = ReasonReact.reducerComponent("Game");
    let make = _children => {
    ...component,
    initialState: () => { board: […], gameState:… },
    reducer: (action: action, state: state) =>
    switch (action) {
    | Restart => …
    | ClickSquare((id: string)) => …
    },
    render: ({state, send}) =>

    state
    onRestart=(_evt => send(Restart))
    onMark=(id => send(ClickSquare(id)))
    />
    ,
    };

    View Slide

  71. @coding_lawyer
    let component = ReasonReact.reducerComponent("Game");
    let make = _children => {
    ...component,
    initialState: () => { board: […], gameState:… },
    reducer: (action: action, state: state) =>
    switch (action) {
    | Restart => …
    | ClickSquare((id: string)) => …
    },
    render: ({state, send}) =>

    state
    onRestart=(_evt => send(Restart))
    onMark=(id => send(ClickSquare(id)))
    />
    ,
    };

    View Slide

  72. @coding_lawyer
    let component = ReasonReact.reducerComponent("Game");
    let make = _children => {
    ...component,
    initialState: () => { board: […], gameState:… },
    reducer: (action: action, state: state) =>
    switch (action) {
    | Restart => …
    | ClickSquare((id: string)) => …
    },
    render: ({state, send}) =>

    state
    onRestart=(_evt => send(Restart))
    onMark=(id => send(ClickSquare(id)))
    />
    ,
    };

    View Slide

  73. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  74. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  75. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  76. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  77. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  78. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  79. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  80. @coding_lawyer
    let component = ReasonReact.reducerComponent("Game");
    let make = _children => {
    ...component,
    initialState: () => { board: […], gameState:… },
    reducer: (action: action, state: state) =>
    switch (action) {
    | Restart => …
    | ClickSquare((id: string)) => …
    },
    render: ({state, send}) =>

    state
    onRestart=(_evt => send(Restart))
    onMark=(id => send(ClickSquare(id)))
    />
    ,
    };

    View Slide

  81. @coding_lawyer
    let component = ReasonReact.reducerComponent("Game");
    let make = _children => {
    ...component,
    initialState: () => { board: […], gameState:… },
    reducer: (action: action, state: state) =>
    switch (action) {
    | Restart => …
    | ClickSquare((id: string)) => …
    },
    render: ({state, send}) =>

    state
    onRestart=(_evt => send(Restart))
    onMark=(id => send(ClickSquare(id)))
    />
    ,
    };

    View Slide

  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,
    });
    },

    View Slide

  83. @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,
    });
    },

    View Slide

  84. @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")),
    );
    },

    View Slide

  85. @coding_lawyer
    pure state update and side-effects
    separation

    View Slide

  86. @coding_lawyer
    less boilerplate

    View Slide

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

    View Slide

  88. @coding_lawyer
    type system

    View Slide

  89. @coding_lawyer
    clearer and safer code

    View Slide

  90. @coding_lawyer
    superior to Flow and TypeScript

    View Slide

  91. @coding_lawyer
    type inference

    View Slide

  92. @coding_lawyer
    !/* type inference by the compiler !*/
    let plus = (a, b) !=> a + b

    View Slide

  93. @coding_lawyer
    !/* type inference by the compiler !*/
    let plus = (a, b) !=> a + b
    !/* (int, int) !=> int !*/

    View Slide

  94. @coding_lawyer
    type field =
    | Empty
    | Marked(player);
    type gameState =
    | Playing(player)
    | Winner(player)
    | Draw;
    type player =
    | Cross
    | Circle;

    View Slide

  95. @coding_lawyer
    type field =
    | Empty
    | Marked(player);
    type gameState =
    | Playing(player)
    | Winner(player)
    | Draw;
    type player =
    | Cross
    | Circle;

    View Slide

  96. @coding_lawyer
    type field =
    | Empty
    | Marked(player);
    type gameState =
    | Playing(player)
    | Winner(player)
    | Draw;
    type player =
    | Cross
    | Circle;

    View Slide

  97. @coding_lawyer
    type field =
    | Empty
    | Marked(player);
    type gameState =
    | Playing(player)
    | Winner(player)
    | Draw;
    type player =
    | Cross
    | Circle;

    View Slide

  98. @coding_lawyer
    type field =
    | Empty
    | Marked(player);
    type gameState =
    | Playing(player)
    | Winner(player)
    | Draw;
    type player =
    | Cross
    | Circle;

    View Slide

  99. @coding_lawyer

    View Slide

  100. @coding_lawyer
    pattern matching

    View Slide

  101. @coding_lawyer
    Game
    Board
    App
    BoardRow
    Square

    View Slide

  102. @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,
    });
    },

    View Slide

  103. @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) {
    | (Playing(_), Marked(_)) => value
    | (Playing(player), Empty) => Marked(player)
    | (_, _) => Empty
    } :
    value
    )
    );

    View Slide

  104. @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) {
    | (Playing(_), Marked(_)) => value
    | (Playing(player), Empty) => Marked(player)
    | (_, _) => Empty
    } :
    value
    )
    );

    View Slide

  105. @coding_lawyer
    type field =
    | Empty
    | Marked(player);
    type gameState =
    | Playing(player)
    | Winner(player)
    | Draw;

    View Slide

  106. @coding_lawyer
    /* determines the value of the clicked square */
    switch (gameState: gameState, value: field) {
    | (Playing(_), Marked(_)) => value
    | (Playing(player), Empty) => Marked(player)
    | (_, _) => Empty
    }

    View Slide

  107. @coding_lawyer
    /* determines the value of the clicked square */
    switch (gameState: gameState, value: field) {
    | (Playing(_), Marked(_)) => value
    | (Playing(player), Empty) => Marked(player)
    | (_, _) => Empty
    }

    View Slide

  108. @coding_lawyer
    /* determines the value of the clicked square */
    switch (gameState: gameState, value: field) {
    | (Playing(_), Marked(_)) => value
    | (Playing(player), Empty) => Marked(player)
    | (_, _) => Empty
    }

    View Slide

  109. @coding_lawyer
    /* determines the value of the clicked square */
    switch (gameState: gameState, value: field) {
    | (Playing(_), Marked(_)) => value
    | (Playing(player), Empty) => Marked(player)
    | (_, _) => Empty
    }

    View Slide

  110. @coding_lawyer
    /* determines the value of the clicked square */
    switch (gameState: gameState, value: field) {
    | (Playing(_), Marked(_)) => value
    | (Playing(player), Empty) => Marked(player)
    | (_, _) => Empty
    }

    View Slide

  111. @coding_lawyer
    /* determines the value of the clicked square */
    switch (gameState: gameState, value: field) {
    | (Playing(_), Marked(_)) => value
    | (Playing(player), Empty) => Marked(player)
    | (_, _) => Empty
    }

    View Slide

  112. @coding_lawyer
    /* determines the value of the clicked square */
    switch (gameState: gameState, value: field) {
    | (Playing(_), Marked(_)) => value
    | (Playing(player), Empty) => Marked(player)
    | (_, _) => Empty
    }

    View Slide

  113. @coding_lawyer
    /* determines the value of the clicked square */
    switch (gameState: gameState, value: field) {
    | (Playing(_), Marked(_)) => value
    | (Playing(player), Empty) => Marked(player)
    /* | (_, _) => Empty */
    }

    View Slide

  114. @coding_lawyer

    View Slide

  115. @coding_lawyer
    switch (
    getWinner(flattenBoard, head),
    gameEnded(flattenBoard),
    tail,
    ) {
    | (Cross, _, _) => Winner(Cross)
    | (Circle, _, _) => Winner(Circle)
    | (_, true, []) => Draw
    | (_, false, []) => whosPlaying(gameState)
    | _ => check(tail)
    };

    View Slide

  116. @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);
    }
    }

    View Slide

  117. @coding_lawyer
    Why should you use React in
    Reason?

    View Slide

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

    View Slide

  119. @coding_lawyer
    strong type system

    View Slide

  120. @coding_lawyer
    pattern matching

    View Slide

  121. @coding_lawyer
    functional programming features

    View Slide

  122. @coding_lawyer
    stateless and stateful component
    separation

    View Slide

  123. @coding_lawyer
    JavaScript-like syntax
    React friendly

    View Slide

  124. @coding_lawyer
    Get your hands dirty!
    sketch.sh

    View Slide

  125. @coding_lawyer

    codinglawyer.io
    @coding_lawyer

    View Slide

  126. @coding_lawyer
    Thank You

    View Slide

  127. @coding_lawyer
    @coding_lawyer
    codinglawyer.io
    github.com/codinglawyer/reason-tic-tac-toe

    View Slide