$30 off During Our Annual Pro Sale. View Details »

🇬🇧 React Advanced 2022

🇬🇧 React Advanced 2022

ℹ️ Deep diving on Concurrent React

Writing fluid user interfaces become more and more challenging as the application complexity increases. In this talk, we’ll explore how proper scheduling improves your app’s experience by diving into some concurrent React features, understanding their rationales, and how they work under the hood.

Matheus Albuquerque

October 21, 2022
Tweet

More Decks by Matheus Albuquerque

Other Decks in Programming

Transcript

  1. Hello, React Advanced! 👋 🇬🇧
    DEEP DIVING ON CONCURRENT REACT • THE 21ST OF OCTOBER, 2022.

    View Slide

  2. DEEP DIVING ON
    CONCURRENT REACT
    MATHEUS ALBUQUERQUE

    View Slide

  3. DEEP DIVING ON CONCURRENT REACT
    🧑🏫 @techlabs
    🐦 @ythecombinator
    👨💻 @medallia
    ↑ ALL THE LINKS! 🤓

    View Slide

  4. View Slide

  5. DEEP DIVING ON CONCURRENT REACT
    🤿
    DEEP DIVE! LET’S
    DISCUSS MORE IN
    THE AFTER CONF!
    ↑ ALL THE LINKS! 🤓

    View Slide

  6. #QUESTION 🤔


    If you were to summarize Concurrent
    React in one word/expression, what’d
    be your pick?

    View Slide

  7. #QUESTION 🤔


    If you were to summarize Concurrent
    React in one word/expression, what’d
    be your pick? e.g.


    fibers = units of work


    Concurrent React = ???

    View Slide

  8. DEEP DIVING ON CONCURRENT REACT
    1st/2nd/3rd ANSWERS ↝ MEDALLIA SWAG


    OTHERS ↝ STICKERS 💅
    If you were to summarize
    Concurrent React in one
    word/expression, what’d
    be your pick?

    View Slide

  9. The Main Thread
    DEEP DIVING ON CONCURRENT REACT

    View Slide

  10. LONG TASKS

    View Slide

  11. View Slide

  12. LONG TASKS

    View Slide

  13. LONG TASKS

    View Slide

  14. #RESEARCH 📚


    Phone users experience slow First
    Input Delay on 7x more websites.


    — Web Almanac By HTTP Archive, 2021

    View Slide

  15. RESEARCH RESULTS:


    ↝ LONG TASKS DELAYED TTI


    ↝ MOBILE HAD UP TO ˜12X LONGER LONG TASKS


    ↝ OLDER DEVICES COULD BE SPENDING HALF OF
    THEIR LOAD-TIME ON LONG TASKS
    — AKAMAI AND CHROME RESEARCH, 2017
    LONG TASKS

    View Slide

  16. — AKAMAI AND CHROME RESEARCH, 2017
    BUSINESS OUTCOMES

    View Slide

  17. #QUESTION 🤔


    How to avoid blocking the main
    thread?

    View Slide

  18. TASK RUNNING STRATEGIES
    A B C D

    View Slide

  19. TASK RUNNING STRATEGIES
    PARALLELISM
    CONCURRENCY
    SCHEDULING

    View Slide

  20. TASK RUNNING STRATEGIES
    PARALLELISM
    CONCURRENCY
    SCHEDULING

    View Slide

  21. WORKERS
    ↝ DATA EXCHANGE IS THROUGH MESSAGE-PASSING


    ↝ NO ACCESS TO ANY VARIABLES/CODE FROM THE
    PAGE THAT CREATED THEM OR VICE VERSA


    ↝ NO ACCESS TO THE DOM, MAKING UI UPDATES
    FROM A WORKER BARELY IMPOSSIBLE


    ↝ TWO MODELS: ACTORS & SHARED MEMORY 🤿

    View Slide

  22. 🎭 ACTORS
    WORKERS
    ↝ EACH ACTOR FULLY OWNS THE DATA IT IS OPERATING ON


    ↝ ACTORS CAN ONLY SEND/REACT TO MESSAGES


    ↝ THE MAIN THREAD IS ACTOR THAT OWNS THE DOM/UI


    ↝ postMessage HAS NO BUILT-IN UNDERSTANDING OF
    REQUEST AND RESPONSE


    ↝ BALANCE: MOVING CODE TO A WORKER VS COMMUNICATION
    OVERHEAD/WORKER BEING BUSY
    🔗 SHARED MEMORY
    ↝ ONE DEDICATED TYPE: SharedArrayBuffer


    View Slide

  23. 🎭 ACTORS
    WORKERS
    🔗 SHARED MEMORY
    ↝ ONE DEDICATED TYPE: SharedArrayBuffer


    ↝ IF SENT VIA postMessage, THE OTHER END GETS A
    HANDLE TO THE EXACT SAME MEMORY CHUNK


    ↝ MOST OF THE WEB APIS ARE BUILT NO CONCURRENT
    ACCESS TO OBJECTS IN MIND


    ↝ YOU BUILD YOUR OWN CONCURRENT DATA STRUCTURES


    ↝ NO DIRECT WAY OF WORKING ON FAMILIAR OBJECTS/
    ARRAYS; JUST A SERIES OF BYTES
    ↝ EACH ACTOR FULLY OWNS THE DATA IT IS OPERATING ON


    View Slide

  24. WEB ASSEMBLY
    ↝ THE BEST EXPERIENCE FOR SHARED-MEMORY MODEL


    ↝ DOESN’T OFFER THE "COMFORT" OF JAVASCRIPT


    ↝ FASTER WHEN YOU STAY WITHIN WASM


    ↝ JAVASCRIPT IS OFTEN FASTER AT DOM AND HIGH-
    LEVEL UI LIBRARIES CAN BE MORE PERFORMANT
    THAN LOW-LEVEL WASM IMPLEMENTATIONS 🤿

    View Slide

  25. ↝ Atomics


    ↝ BuffferBackedObject


    ↝ Comlink


    ↝ WorkerDOM


    ↝ AND MUCH MORE!

    View Slide

  26. WORKERS
    ↝ GOOD FOR DATA PROCESSING AND CRUNCHING
    NUMBERS


    ↝ HARD TO USE FOR UI-RELATED STUFF


    ↝ HARDER THAN ADJUSTING WORK FOR A SCHEDULER

    View Slide

  27. TASK RUNNING STRATEGIES
    PARALLELISM
    CONCURRENCY
    SCHEDULING

    View Slide

  28. #QUESTION 🤔


    If you were to summarize Concurrent
    React in one word/expression, what’d
    be your pick?

    View Slide

  29. DEEP DIVING ON CONCURRENT REACT
    If you were to summarize
    Concurrent React in one
    word/expression, what’d
    be your pick?

    View Slide

  30. Scheduling in
    React
    DEEP DIVING ON CONCURRENT REACT

    View Slide

  31. HEURISTICS
    COOPERATIVE MULTITASKING WITH A SINGLE
    INTERRUPTIBLE RENDERING THREAD
    PRIORITY LEVELS
    REGISTER CALLBACKS WITH DIFFERENT PRIORITY LEVELS
    IN THE BROWSER
    RENDER LANES
    ABSTRACTIONS AROUND A BITMASK; BRING GRANULARITY,
    AVOID OVERHEAD & ALLOW BATCHING
    SCHEDULING IN REACT

    View Slide

  32. ↝ A COOPERATIVE MULTITASKING MODEL


    ↝ A SINGLE INTERRUPTIBLE RENDERING THREAD


    ↝ RENDERING CAN BE INTERLEAVED WITH OTHER
    MAIN THREAD TASKS (AND OTHER REACT RENDERS)


    ↝ AN UPDATE CAN HAPPEN IN THE BACKGROUND
    WITHOUT BLOCKING THE RESPONSE TO NEW INPUT
    SCHEDULING IN REACT

    View Slide

  33. ↝ IT YIELDS EXECUTION IS BACK TO THE MAIN
    THREAD EVERY 5MS


    ↝ IT'S SMALLER THAN A SINGLE FRAME EVEN ON
    120FPS, SO IT WON'T BLOCK ANIMATIONS


    ↝ IN PRACTICE, RENDERING IS INTERRUPTIBLE
    HEURISTICS

    View Slide

  34. PRIORITY LEVELS

    View Slide

  35. PRIORITY LEVELS

    View Slide

  36. PRIORITY TIMEOUT WHEN
    I
    m
    m
    ediate SYNCHRONOUSLY TASKS THAT NEED TO RUN SYNCHRONOUSLY
    UserBlocking 250MS RESULTS OF A USER INTERACTION (E.G. A BUTTON CLICK)
    Normal 5S UPDATES THAT DON’T HAVE TO FEEL INSTANTANEOUS
    Low 10S
    TASKS THAT CAN BE DEFERRED BUT MUST STILL COMPLETE EVENTUALLY
    (E.G. AN ANALYTICS NOTIFICATION)
    Idle NO TIMEOUT
    TASKS THAT DO NOT HAVE TO RUN AT ALL (E.G. HIDDEN OFFSCREEN
    CONTENT)

    View Slide

  37. ↝ ONE LANE = ONE BIT IN A BITMASK


    ↝ ONE UPDATE IN REACT = ONE LANE


    ↝ UPDATES IN THE SAME LANE RENDER IN THE SAME
    BATCH. DIFFERENT LANES, SEPARATE BATCHES.


    ↝ 31 LEVELS OF GRANULARITY (= ONE BITMASK)
    RENDER LANES
    🤿

    View Slide

  38. ↝ ALLOWS TO CHOOSE WHETHER TO RENDER MULTIPLE
    TRANSITIONS IN A SINGLE BATCH OR RENDER
    THEM INDEPENDENTLY


    ↝ REDUCES OVERHEAD OF MULTIPLE LAYOUT PASSES,
    STYLE RECALCULATIONS, AND MULTIPLE PAINTS
    RENDER LANES
    🤿

    View Slide

  39. View Slide

  40. DEEP DIVING ON CONCURRENT REACT

    View Slide

  41. #QUESTION 🤔


    How do we benefit from these in our
    everyday projects?

    View Slide

  42. Scheduling in
    React


    [for the rest of us]
    DEEP DIVING ON CONCURRENT REACT

    View Slide

  43. SCHEDULING IN REACT
    HANDLING LOTS OF DATA
    WITH THE useTransition HOOK
    TACKLING WASTED RENDERS
    WITH THE useSyncExternalStore HOOK
    HYDRATION IMPROVEMENTS
    WITH SELECTIVE HYDRATION & CONCURRENT REACT
    PROFILER ENHANCEMENTS
    INSPECT TRANSITIONS, GET WARNS, AND MUCH MORE!

    View Slide

  44. #1 HANDLING LARGE
    SETS OF DATA
    DEEP DIVING ON CONCURRENT REACT

    View Slide

  45. 😔 NON-PRACTICAL…


    ↝ FINDING PRIMES


    ↝ CRACKING PASSWORDS


    ↝ SIERPINSKI TRIANGLE

    View Slide

  46. 😔 NON-PRACTICAL…


    ↝ RENDERING MANY DATA-POINTS


    ↝ RENDERING ON A


    ↝ PROCESSING DATA

    View Slide

  47. DAILY VISITORS (BEFORE)

    View Slide

  48. DAILY VISITORS (BEFORE)
    const DailyVisitors
    =
    ()
    =
    >
    {


    const [data, setData]
    =
    useState(initialData);


    useEffect(()
    =
    >
    {


    setData(initialData);


    }, []);


    const onChange
    =
    (newData)
    =
    >
    {


    setData(newData);


    };


    return (





    );


    };


    export default DailyVisitors;

    View Slide

  49. DAILY VISITORS (AFTER)
    const DailyVisitors
    =
    ()
    =
    >
    {


    const [data, setData]
    =
    useState(initialData);


    const [, startTransition]
    =
    useTransition();


    useEffect(()
    =
    >
    {


    setData(initialData);


    }, []);


    const onChange
    =
    (newData)
    =
    >
    {


    startTransition(()
    =
    >
    {


    setData(newData);


    });


    };


    return (





    );


    };


    export default DailyVisitors;

    View Slide

  50. DAILY VISITORS (AFTER)

    View Slide

  51. ↝ ˜100K + POINTS PLOTTED


    ↝ SUPPORT FOR SEARCHING AND FILTERING


    ↝ USED WORKERS + REDUX-SAGA UTILITIES +
    DEBOUNCING


    ↝ COULD'VE USED TRANSITIONS
    CASE #1: MAPS

    View Slide

  52. CASE #2: GAME ADMIN
    ↝ THOUSANDS OF REAL-TIME PLAYERS MESSAGING


    ↝ SUPPORT FOR SEARCHING AND FILTERING


    ↝ USED VIRTUALIZATION AND MEMOIZATION


    ↝ COULD'VE USED TRANSITIONS

    View Slide

  53. #2 TACKLING WASTED
    RENDERS
    DEEP DIVING ON CONCURRENT REACT

    View Slide

  54. useSyncExternalStore()
    function useSyncExternalStore(


    subscribe: (onStoreChange: ()
    =
    >
    void)
    =
    >
    ()
    =
    >
    void,


    getSnapshot: ()
    =
    >
    Snapshot,


    getServerSnapshot?: ()
    =
    >
    Snapshot


    ): Snapshot;

    View Slide

  55. DEEP DIVING ON CONCURRENT REACT

    View Slide

  56. View Slide

  57. #QUESTION 🤔


    How do we benefit from these in our
    everyday projects?

    View Slide

  58. View Slide

  59. useLocation()
    function Pathname() {


    const { pathname }
    =
    useLocation();


    return ;


    }


    function Hash() {


    const { hash }
    =
    useLocation();


    return ;


    }

    View Slide

  60. useLocation()
    function Pathname() {


    const { pathname }
    =
    useLocation();


    return ;


    }


    function Hash() {


    const { hash }
    =
    useLocation();


    return ;


    }
    OVER-RETURNING HOOK

    View Slide

  61. SPEAKERS LIST [BEFORE]

    View Slide

  62. useLocation()
    function Pathname() {


    const { pathname }
    =
    useLocation();


    return ;


    }


    function Hash() {


    const { hash }
    =
    useLocation();


    return ;


    }

    View Slide

  63. useLocation() useHistorySelector()
    function useHistorySelector(selector) {


    const history
    =
    useHistory();


    return useSyncExternalStore(history.listen, ()
    =
    >
    selector(history));


    }


    function Pathname() {


    const pathname
    =
    useHistorySelector((history)
    =
    >
    history.location.pathname);


    return ;


    }


    function Hash() {


    const hash
    =
    useHistorySelector((history)
    =
    >
    history.location.hash);


    return ;


    }

    View Slide

  64. function useHistorySelector(selector) {


    const history
    =
    useHistory();


    return useSyncExternalStore(history.listen, ()
    =
    >
    selector(history));


    }


    function Pathname() {


    const pathname
    =
    useHistorySelector((history)
    =
    >
    history.location.pathname);


    return ;


    }


    function Hash() {


    const hash
    =
    useHistorySelector((history)
    =
    >
    history.location.hash);


    return ;


    }
    useLocation() useHistorySelector()

    View Slide

  65. SPEAKERS LIST [AFTER]

    View Slide

  66. #3 HYDRATION
    IMPROVEMENTS
    DEEP DIVING ON CONCURRENT REACT

    View Slide

  67. ↝ BEFORE, HYDRATION COULD ONLY BEGIN AFTER
    THE ENTIRE DATA WAS FETCHED AND RENDERED


    ↝ USERS COULDN’T INTERACT WITH THE PAGE UNTIL
    HYDRATION WAS COMPLETE FOR THE WHOLE PAGE


    ↝ PARTS OF YOUR APP THAT LOAD FAST WOULD
    ALWAYS HAVE TO WAIT FOR THE SLOW ONES
    HYDRATION

    View Slide

  68. ↝ REACT WON'T WAIT FOR A COMPONENT TO LOAD TO
    CONTINUE STREAMING THE REST OF THE HTML


    ↝ REACT PRIORITIZES HYDRATING THE PARTS THAT
    THE USER INTERACTED WITH BEFORE THE REST
    SELECTIVE HYDRATION

    View Slide

  69. ↝ COMPONENTS CAN BECOME INTERACTIVE FASTER BY
    ALLOWING THE BROWSER TO DO OTHER WORK AT
    THE SAME TIME AS HYDRATION


    ↝ RESULTS IN LOWER FIRST INPUT DELAY (FID)
    AND INTERACTION TO NEXT PAINT (INP)
    SELECTIVE HYDRATION

    View Slide

  70. DEEP DIVING ON CONCURRENT REACT

    View Slide

  71. #4 PROFILER
    ENHANCEMENTS
    DEEP DIVING ON CONCURRENT REACT

    View Slide

  72. TRANSITIONS
    — INTRODUCING A NEW REACT PROFILER, BY BRIAN VAUGHN

    View Slide

  73. — INTRODUCING A NEW REACT PROFILER, BY BRIAN VAUGHN
    WARNS

    View Slide

  74. The Future
    DEEP DIVING ON CONCURRENT REACT

    View Slide

  75. ↝ I/O LIBRARIES LIKE react-fetch


    ↝ BUILT-IN FOR DATA FETCHING
    LIBRARIES TO INTEGRATE WITH


    ↝ FOR CPU-BOUND TREES TO
    IMMEDIATELY FALLBACK WITHOUT EVEN TRYING TO
    RENDER
    THE FUTURE
    🤿

    View Slide

  76. ↝ useInsertionEffect FOR STYLESHEET LIBRARIES


    ↝ THE COMPONENT


    ↝ SERVER COMPONENTS


    ↝ NATIVE SCHEDULING PRIMITIVES ON THE BROWSER
    THE FUTURE
    🤿

    View Slide

  77. DEEP DIVING ON CONCURRENT REACT

    View Slide

  78. SCHEDULING API
    ↝ A MORE ROBUST SOLUTION FOR SCHEDULING TASKS


    ↝ CONTROL AND SCHEDULE PRIORITIZED TASKS IN A
    UNITED AND FLEXIBLE WAY


    ↝ INTEGRATED DIRECTLY INTO THE EVENT LOOP


    ↝ ALIGNED WITH THE WORK OF THE REACT TEAM AND
    IN COOPERATION WITH GOOGLE, W3C AND OTHERS

    View Slide

  79. scheduler.postTask()
    SCHEDULE AND CONTROL PRIORITIZING TASKS.
    scheduler.wait()
    YIELD AND RESUME AFTER SOME AMOUNT OF TIME OR
    PERHAPS AFTER AN EVENT HAS OCCURRED.
    scheduler.yield()
    BREAK UP LONG TASKS BY YIELDING TO THE BROWSER AND
    CONTINUING AFTER BEING RESCHEDULED.
    isInputPending()
    DETERMINE IF THE CURRENT TASK IS BLOCKING INPUT
    EVENTS.
    SCHEDULING API

    View Slide

  80. SCHEDULING API

    View Slide

  81. Closing Notes
    DEEP DIVING ON CONCURRENT REACT

    View Slide

  82. DEEP DIVING ON CONCURRENT REACT

    View Slide

  83. #1
    DEEP DIVING ON CONCURRENT REACT
    REACT IS NOT
    REACTIVE, BUT IT
    IS CONCURRENT


    AND THAT MIGHT BE ENOUGH FOR YOU

    View Slide

  84. View Slide

  85. #2
    DEEP DIVING ON CONCURRENT REACT
    REACT HAS BEEN
    PUSHING WEB APIS
    TO THE FUTURE


    E.G. THE SCHEDULER API

    View Slide

  86. DEEP DIVING ON CONCURRENT REACT

    View Slide

  87. 🤿

    View Slide

  88. export const Hello
    =
    ()
    =
    >
    {


    const value
    =
    usePromise(()
    =
    >
    delay("Hello, React Advanced! 👋 🇬🇧 ", 5000));


    return {value};


    };


    function Demo() {


    return (





    }>











    );


    }
    🤿

    View Slide

  89. DID WE JUST CREATE


    React.use()? 🤔

    View Slide

  90. YES, WE DID 🤓

    View Slide

  91. #3
    DEEP DIVING ON CONCURRENT REACT
    UNDERSTANDING
    THESE INTERNALS
    AND THEIR
    RATIONALES HELPS
    US IMPLEMENT OUR
    OWN ABSTRACTIONS


    E.G. FIRST CLASS SUPPORT FOR PROMISES

    View Slide

  92. #4
    DEEP DIVING ON CONCURRENT REACT
    SCHEDULING DOES
    NOT NECESSARILY
    MEAN BETTER
    PERFORMANCE
    🤿

    View Slide

  93. #5
    DEEP DIVING ON CONCURRENT REACT
    THERE'S NO
    SILVER BULLET.
    IDENTIFY YOUR
    CORE METRICS.

    View Slide

  94. #6
    DEEP DIVING ON CONCURRENT REACT
    THERE’S A LOT OF
    INFORMATION OUT
    THERE

    View Slide

  95. View Slide

  96. #7
    DEEP DIVING ON CONCURRENT REACT
    ALWAYS TRY TO
    CORRELATE
    BUSINESS METRICS
    WITH PERFORMANCE

    View Slide

  97. DEEP DIVING ON CONCURRENT REACT

    View Slide

  98. View Slide

  99. DEEP DIVING ON CONCURRENT REACT
    THAT’S ALL, FOLKS!


    THANKS! 🤝 🇬🇧


    QUESTIONS?
    MATHEUS ALBUQUERQUE
    ↑ ALL THE LINKS! 🤓

    View Slide