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

๐Ÿ‡ฎ๐Ÿ‡ณ React India 2023

๐Ÿ‡ฎ๐Ÿ‡ณ React Indiaย 2023

โ„น๏ธ Inside Fiber: the in-depth overview you wanted a TLDR for

We'll have an in-depth overview of the important concepts behind reconciliation and React Fiber. Then, we'll explore how React uses this algorithm and go through a few magic words we hear a lot, like coroutines, continuations, generators, and algebraic effectsโ€”and see how they all relate to React.

Matheus Albuquerque

October 03, 2023
Tweet

More Decks by Matheus Albuquerque

Other Decks in Programming

Transcript

  1. function add(x,y) { const result = x + y; return

    result; } add(2, 2) STACK FRAMES
  2. let frame: Frame = { return: frame, fn: add, parameters:

    [2, 2], localVariables: { result: 4, }, } STACK FRAMES
  3. let frame: Frame = { return: frame, fn: add, parameters:

    [2, 2], localVariables: { result: 4, }, } let fiber: Fiber = { return: fiber, component: Avatar, props: { id: 4 }, state: { isLoaded: true, }, } STACK FRAMES
  4. โ† FIBER ARCHITECTURE โ‡ข REACT-SPECIFIC IMPLEMENTATION OF A CALL-STACK-LIKE MODEL

    WHERE REACT HAS FULL CONTROL OF SCHEDULING WHAT SHOULD BE DONE โ† FIBER โ‡ข A STACK FRAME FOR A REACT COMPONENT FIBERS
  5. ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END

    UP WITH A BUNCH OF REACT ELEMENTS. DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT RETURNED FROM THE RENDER METHOD IS MERGED INTO THE TREE OF FIBER NODES. DEPENDING ON THE TYPE OF A REACT ELEMENT THE FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE.
  6. ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END

    UP WITH A BUNCH OF REACT ELEMENTS. DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT RETURNED FROM THE RENDER METHOD IS MERGED INTO THE TREE OF FIBER NODES. DEPENDING ON THE TYPE OF A REACT ELEMENT THE FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE.
  7. ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END

    UP WITH A BUNCH OF REACT ELEMENTS. DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT RETURNED FROM THE RENDER METHOD IS MERGED INTO THE TREE OF FIBER NODES. DEPENDING ON THE TYPE OF A REACT ELEMENT THE FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE.
  8. ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END

    UP WITH A BUNCH OF REACT ELEMENTS. DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT RETURNED FROM THE RENDER METHOD IS MERGED INTO THE TREE OF FIBER NODES. DEPENDING ON THE TYPE OF A REACT ELEMENT THE FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE.
  9. ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END

    UP WITH A BUNCH OF REACT ELEMENTS. DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT RETURNED FROM THE RENDER METHOD IS MERGED INTO THE TREE OF FIBER NODES. DEPENDING ON THE TYPE OF A REACT ELEMENT THE FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE. A UNIT OF WORK.
  10. ONCE A TEMPLATE GOES THROUGH THE JSX COMPILER, YOU END

    UP WITH A BUNCH OF REACT ELEMENTS. DURING RECONCILIATION, DATA FROM EVERY REACT ELEMENT RETURNED FROM THE RENDER METHOD IS MERGED INTO THE TREE OF FIBER NODES. DEPENDING ON THE TYPE OF A REACT ELEMENT THE FRAMEWORK NEEDS TO PERFORM DIFFERENT ACTIVITIES. EACH ELEMENT IS CONVERTED INTO A FIBER NODE THAT DESCRIBES THE WORK THAT NEEDS TO BE DONE. A UNIT OF WORK. AND THAT MAKES IT A CONVENIENT WAY TO TRACK, SCHEDULE, PAUSE AND ABORT THE WORK.
  11. let fiberNode = fiberRoot.current; let fibersMap = new Map(); while

    (fiberNode) { if (fiberNode.stateNode ! = = null) { fibersMap.set(fiberNode.stateNode, fiberNode); } if (fiberNode.child === null) { while (fiberNode ! = = null & & fiberNode.sibling === null) { fiberNode = fiberNode.return; } fiberNode = fiberNode?.sibling; continue; } fiberNode = fiberNode.child; }
  12. let fiberNode = fiberRoot.current; let fibersMap = new Map(); while

    (fiberNode) { if (fiberNode.stateNode ! = = null) { fibersMap.set(fiberNode.stateNode, fiberNode); } if (fiberNode.child === null) { while (fiberNode ! = = null & & fiberNode.sibling === null) { fiberNode = fiberNode.return; } fiberNode = fiberNode?.sibling; continue; } fiberNode = fiberNode.child; } ๐Ÿคฏ
  13. (let [x 1] (inc x)) ; = > 2 HOMOICONICITY

    PERFORMS A TEMPORARY BINDING (BINDS X TO THE VALUE 1)
  14. INCREMENTS X TO GIVE THE RETURN VALUE OF 2 (let

    [x 1] (inc x)) ; = > 2 HOMOICONICITY
  15. IT CAN BE THOUGHT OF AS A LIST WITH THREE

    ELEMENTS โ† A SYMBOL NAMED LET โ† A VECTOR WITH TWO ELEMENTS โ† A LIST WITH TWO ELEMENTS HOMOICONICITY
  16. IT CAN BE THOUGHT OF AS A LIST WITH THREE

    ELEMENTS โ† A SYMBOL NAMED LET โ† A VECTOR WITH TWO ELEMENTS โ† A LIST WITH TWO ELEMENTS HOMOICONICITY A SYMBOL (X) AND AN INTEGER A SYMBOL (INC) AND A SYMBOL (X)
  17. #QUOTE ๐Ÿค” โ€œโ€ฆHomoiconicity is a property of some programming languages

    in which the code used to express a program is written using the data structures of that language.โ€ โ€”โ€‰Wikipedia
  18. โ† REACT ELEMENTS ARE JUST DATA โ† JUST LIKE IN

    LISP, REACT COMPONENTS CAN MANIPULATE THEIR CHILDREN AND RETURN COMPLETELY DIFFERENT THINGS HOMOICONICITY
  19. #QUOTE ๐Ÿค” โ€œ[โ€ฆ] Pattern matching consists of specifying patterns to

    which some data should conform and then checking to see if it does and deconstructing the data according to those patterns.โ€ โ€”โ€‰Learn You a Haskell
  20. factorial : : (Integral a) = > a - >

    a factorial 0 = 1 factorial n = n * factorial (n - 1) PATTERN MATCHING
  21. fib : : (Integral a) = > a - >

    a fib 0 = 1 fib 1 = 1 fib n | n > = 2 = fib (n-1) + fib (n-2) PATTERN MATCHING factorial factorial 0 factorial n =
  22. / / . . . export function isWhen<Shape extends {}>(

    child: ElementWithMetadataUnion<Shape> ): child is ElementWithMetadata<WhenProps<Shape > > { return child.element.type === When; } / / . . . export function nodesToElementWithMetadata<Shape extends {}>( children: ReactNode ) { return Children.toArray(children).map((element, idx) = > ({ element: element, position: idx, })) as Array<ElementWithMetadata<Shape > > ; } / / . . .
  23. / / . . . export function isWhen<Shape extends {}>(

    child: ElementWithMetadataUnion<Shape> ): child is ElementWithMetadata<WhenProps<Shape > > { return child.element.type === When; } / / . . . export function nodesToElementWithMetadata<Shape extends {}>( children: ReactNode ) { return Children.toArray(children).map((element, idx) = > ({ element: element, position: idx, })) as Array<ElementWithMetadata<Shape > > ; } / / . . .
  24. const supportsSensor = () = > Boolean(window.AmbientLightSensor); const AmbientLight =

    React.lazy(() = > import("./AmbientLight")); const Fallback = React.lazy(() = > import("./Fallback")); export default function MyComponent() { const { Match, When, Otherwise } = usePatternMatch(); return ( <Suspense fallback="Loading"> <Match> <When predicate={supportsSensor}> <AmbientLight /> </When> <Otherwise> <Fallback /> </Otherwise> </Match> </Suspense> ); } PATTERN MATCHING
  25. const supportsSensor = () = > Boolean(window.AmbientLightSensor); const AmbientLight =

    React.lazy(() = > import("./AmbientLight")); const Fallback = React.lazy(() = > import("./Fallback")); export default function MyComponent() { const { Match, When, Otherwise } = usePatternMatch(); return ( <Suspense fallback="Loading"> <Match> <When predicate={supportsSensor}> <AmbientLight /> </When> <Otherwise> <Fallback /> </Otherwise> </Match> </Suspense> ); } PATTERN MATCHING + REACT.SUSPENSE + REACT.LAZY() = USERS DOWNLOAD ONLY THE COMPONENT BUNDLE THAT MATCHES
  26. const supportsSensor const AmbientLight const Fallback export default function MyComponent()

    { const { Match, When, Otherwise } return ( <Suspense fallback="Loading"> <Match> <When predicate={supportsSensor}> <AmbientLight /> </When> <Otherwise> <Fallback /> </Otherwise> </Match> </Suspense> ); } PATTERN MATCHING + REACT.SUSPENSE + REACT.LAZY() = USERS DOWNLOAD ONLY THE COMPONENT BUNDLE THAT MATCHES MANIPULATING BASED ON ELEMENTS DATA.
  27. USING FIBERS, REACT CAN: โ† PAUSE, RESUME, AND RESTART RENDERING

    WORK ON COMPONENTS AS NEW UPDATES COME IN โ† REUSE PREVIOUSLY COMPLETED WORK โ† SPLIT WORK INTO CHUNKS AND PRIORITIZE TASKS BASED ON IMPORTANCE FIBERS IN REACT (RECAP)
  28. โ† A FIBER IS A GENERIC MODEL OF EXECUTION WHERE

    EACH UNIT WORKS TOGETHER COOPERATIVELY โ† FIBERS ARE A COMMON RESOURCE IN SOME OPERATING SYSTEMS (E.G. WINDOWS) AND IN SOME PROGRAMMING LANGUAGES (E.G. OCAML) FIBERS OUT THERE
  29. #1 THE COMPUTER SCIENCE OF FIBERS โ† JAVASCRIPT GENERATORS CAN

    CONSUME VALUES โ† BY THIS DEFINITION, THEY ARE COROUTINES A GENERATOR (PRODUCER) THAT CAN ALSO CONSUME VALUES.
  30. #2 THE COMPUTER SCIENCE OF FIBERS โ† THIS IS THE

    MOST COMMON MEANING OF โ€œCOROUTINEโ€ IN THE JAVASCRIPT WORLD โ† WE HAD CO AND BLUEBIRD, WHICH HAD ASYNC/AWAIT IMPLEMENTATIONS BASED ON GENERATORS VALUES, LIKE ASYNC/AWAIT.
  31. #3 THE COMPUTER SCIENCE OF FIBERS โ† "DEEP AWAIT" โ†

    e.g. WITH SUSPENSE, WE CAN PAUSE RECONCILIATION AT ANY DEPTH A GENERATOR THAT CAN YIELD WITH A STACKFUL CONTINUATION
  32. Fibers CONTROL IS PASSED TO A SCHEDULER WHICH DETERMINES WHAT

    TO RUN NEXT โ† = CONTROLLED AT THE LEVEL OF THE OPERATING SYSTEM OR FRAMEWORK โ† E.G. NODE.JS EVENT LOOP
  33. Coroutines CONTROL IS PASSED TO THE CALLER AND HANDLED BY

    APPLICATION CODE Fibers CONTROL IS PASSED TO A SCHEDULER WHICH DETERMINES WHAT TO RUN NEXT
  34. COROUTINES APPEARED WHEN WORK ON FIBER WAS FIRST GOING AS

    A SPECIFIC COMPONENT TYPE. THE IDEA BEHIND COROUTINESโ€Šโ€”โ€ŠAS OPPOSED TO FIBERSโ€Šโ€”โ€ŠWAS TO GIVE COMPONENTS EXPLICIT CONTROL OVER YIELDING AND RESUMPTION.
  35. COROUTINES & REACT โ† COROUTINES PER SI IN REACT NO

    LONGER EXIST. โ† IT WILL BE FASCINATING TO SEE WHAT FORM COROUTINES TAKE WHEN THEY RETURN TO REACT FIBER.
  36. function resourcefulOperation(value: number) { let newValue = String(value); for (let

    i = 0; i < 1000000; i++) { newValue = `${value} + ${i} = ${value + i}`; } return newValue; } function ResourcefulComponent(props: { value: number }) { const { value } = props; const result = resourcefulOperation(value); return <p>{result}</p>; }
  37. function resourcefulOperation(value: number) { let newValue = String(value); for (let

    i = 0; i < 1000000; i++) { newValue = `${value} + ${i} = ${value + i}`; } return newValue; } function ResourcefulComponent(props: { value: number }) { const { value } = props; const result = resourcefulOperation(value); return <p>{result}</p>; }
  38. function* resourcefulOperation(value: number) { let newValue = String(value); while (true)

    { yield; for (let i = 0; i < 1000000; i++) { newValue = `${value} + ${i} = ${value + i}`; } return newValue; } } const initialValue = 0; const scheduler = new Scheduler(resourcefulOperation, initialValue); function ResourcefulComponent(props: { value: number }) { const { value } = props; const result = scheduler.performUnitOfWork(value); return <p>{result}</p>; }
  39. function* resourcefulOperation(value: number) { let newValue = String(value); while (true)

    { yield; for (let i = 0; i < 1000000; i++) { newValue = `${value} + ${i} = ${value + i}`; } return newValue; } } const initialValue = 0; const scheduler = new Scheduler(resourcefulOperation, initialValue); function ResourcefulComponent(props: { value: number }) { const { value } = props; const result = scheduler.performUnitOfWork(value); return <p>{result}</p>; } PROMOTED TO A GENERATOR YIELDING EXECUTION DOING CONCURRENT TASKS
  40. enum SchedulerState { IDLE = "IDLE", PENDING = "PENDING", DONE

    = "DONE", } class Scheduler<T> { state: SchedulerState; result: T; worker: (data: T) = > Generator; iterator: Generator; constructor(worker: (data: T) = > Generator, initialResult: T) { this.state = SchedulerState.IDLE; this.worker = worker; this.result = initialResult; } performUnitOfWork(data: T) { switch (this.state) { case "IDLE": this.state = SchedulerState.PENDING; this.iterator = this.worker(data); throw Promise.resolve(); case "PENDING": const { value, done } = this.iterator.next(); if (done) { this.result = value; this.state = SchedulerState.DONE; return value; } throw Promise.resolve(); case "DONE": this.state = SchedulerState.IDLE; return this.result; } } }
  41. performUnitOfWork(data: T) { switch (this.state) { case "IDLE": this.state =

    SchedulerState.PENDING; this.iterator = this.worker(data); throw Promise.resolve(); case "PENDING": const { value, done } = this.iterator.next(); if (done) { this.result = value; this.state = SchedulerState.DONE; return value; } throw Promise.resolve(); case "DONE": this.state = SchedulerState.IDLE; return this.result; } }
  42. function resourcefulOperation(value: number) { let newValue = String(value); for (let

    i = 0; i < 1000000; i++) { newValue = `${value} + ${i} = ${value + i}`; } return newValue; } function ResourcefulComponent(props: { value: number }) { const { value } = props; const result = resourcefulOperation(value); return <p>{result}</p>; }
  43. function resourcefulOperation(value: number) { let newValue = String(value); for (let

    i = 0; i < 1000000; i++) { newValue = `${value} + ${i} = ${value + i}`; } return newValue; } function ResourcefulComponent(props: { value: number }) { const [_, startTransition] = useTransition(); const [result, setResult] = useState(""); useEffect(() = > { startTransition(() = > { const newResult = resourcefulOperation(props.value); setResult(newResult); }); }, [props.value]); return <p>{result}</p>; }
  44. โ† 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 COROUTINES & SCHEDULING
  45. โ†“ ORIGINAL RENDER TASK USER INPUT โ†’ โ†‘ HIGHER PRIORITY

    RENDER TASK โ†“ RESUME ORIGINAL RENDER TASK
  46. โ† 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 COROUTINES & SCHEDULING
  47. โ† ASYNCHRONY IN JAVASCRIPT IS CONTAGIOUS โ† IF ANY FUNCTION

    IS ASYNC, THEN EVERYTHING THAT CALLS IT MUST ALSO BE ASYNCโ€ฆ โ† โ€ฆAND SO ON UNTIL THE ENTIRE PROGRAM IS ASYNCHRONOUS ๐Ÿคท ASYNCHRONY & JS
  48. โ† ASYNCHRONY IN JAVASCRIPT ISNโ€™T FREE โ† EVERY ASYNCHRONOUS FUNCTION

    CALL HAS TO: โ† ALLOCATE CALLBACKS & STORE THEM SOMEWHERE โ† TAKE A TRIP BACK TO THE EVENT LOOP BEFORE INVOKING THOSE CALLBACKS ASYNCHRONY & JS
  49. โ† ITS API HAS TWO MAIN FUNCTIONS FOR COMPILING SASS

    FILES: ONE SYNC AND ONE ASYNC โ† THE ASYNC ONE BECAME WIDELY USED IN PRACTICE BECAUSE IT ENABLED ASYNC PLUGINS (E.G. WEBPACKโ€™S SASS-LOADER) ASYNCHRONY & SASS
  50. โ† FOR NODE SASS, THE PERFORMANCE DIFFERENCE WAS NEGLIGIBLE, BECAUSE

    IT WAS BUILT ON C++ โ† HOWEVER, DART SASS RUNS AS PURE JAVASCRIPT, WHICH MAKES IT SUBJECT TO JAVASCRIPTโ€™S ASYNC RULES ASYNCHRONY & SASS
  51. โ† THE ASYNC VERSION IN DART SASS WAS 2-3X SLOWER

    THAN THE SYNC ONE โ† THEY STARTED USING NODE-FIBERS TO IMPLEMENT THE ASYNC API USING THE FAST, SYNC, CODE ASYNCHRONY & SASS
  52. ๐Ÿคฏ APPROACH TO REASONING ABOUT COMPUTATIONAL EFFECTS IN PURE CONTEXTS

    โ† EFFECT โ‡ข A SET OF OPERATIONS โ† EFFECT HANDLER โ‡ข RESPONSIBLE FOR HANDLING THE SEMANTICS OF HOW TO IMPLEMENT EFFECTS EFFECT HANDLERS
  53. (* state.eff *) type user = string * int effect

    Get: user effect Set: user - > unit ๐Ÿคฏ EFFECT HANDLERS IN EFF
  54. (* state.eff *) type user = string * int effect

    Get: user effect Set: user - > unit A USER WITH A NAME AND AGE EFFECT HANDLERS IN EFF
  55. (* state.eff *) type user = string * int effect

    Get: user effect Set: user - > unit WE DEFINE EFFECTS WITH THE effect KEYWORD AND A TYPE SIGNATURE. EFFECT HANDLERS IN EFF
  56. let state = handler | y - > fun currentState

    - > (y, currentState) | effect Get k - > (fun currentState - > (continue k currentState) currentState) | effect (Set newState) k - > (fun _ - > (continue k ()) newState) ;; ๐Ÿคฏ EFFECT HANDLERS IN EFF
  57. let state = handler | y - > fun currentState

    - > (y, currentState) | effect Get k - > (fun currentState - > (continue k currentState) currentState) | effect (Set newState) k - > (fun _ - > (continue k ()) newState) ;; WE HAVE A handler WITH THREE BRANCHES, AND ALL OF THEM RETURN A FUNCTION. EFFECT HANDLERS IN EFF
  58. let state = handler | y - > fun currentState

    - > (y, currentState) | effect Get k - > (fun currentState - > (continue k currentState) currentState) | effect (Set newState) k - > (fun _ - > (continue k ()) newState) ;; NO EFFECT (WHEN WE REACH THE END OF THE BLOCK). y IS THE RETURN VALUE. EFFECT HANDLERS IN EFF
  59. let state = handler | y - > fun currentState

    - > (y, currentState) | effect Get k - > (fun currentState - > (continue k currentState) currentState) | effect (Set newState) k - > (fun _ - > (continue k ()) newState) ;; MATCHING OUR EFFECTS. EFFECT HANDLERS IN EFF
  60. let state = handler | y - > fun currentState

    - > (y, currentState) | effect Get k - > (fun currentState - > (continue k currentState) currentState) | effect (Set newState) k - > (fun _ - > (continue k ()) newState) ;; k IS A CONTINUATION. IT REPRESENTS THE REST OF THE COMPUTATION AFTER WHERE WE PERFORM AN EFFECT. EFFECT HANDLERS IN EFF
  61. function getName(user) { let name = user.name; if (name ===

    null) { name = perform 'ask_name'; } return name; } const arya = { name: null, friendNames: [] }; const gendry = { name: 'Gendry', friendNames: [] }; try { getName(arya); } handle (effect) { if (effect === 'ask_name') { resume with 'Arya Stark'; } }
  62. function getName(user) { let name = user.name; if (name ===

    null) { name = perform 'ask_name'; } return name; } const arya = { name: null, friendNames: [] }; const gendry = { name: 'Gendry', friendNames: [] }; try { getName(arya); } handle (effect) { if (effect === 'ask_name') { resume with 'Arya Stark'; } }
  63. function getName(user) { let name = user.name; if (name ===

    null) { name = perform 'ask_name'; } return name; } const arya = { name: null, friendNames: [] }; const gendry = { name: 'Gendry', friendNames: [] }; try { getName(arya); } handle (effect) { if (effect === 'ask_name') { resume with 'Arya Stark'; } } THROW โ†’ PERFORM CATCH โ†’ HANDLE LETS US JUMP BACK TO WHERE WE PERFORMED THE EFFECT
  64. โ† IT DOESN'T REALLY MATTER HOW WE HOLD STATE. IF

    WE WERE TO CHANGE IN THE FUTURE, WEโ€™D NEED TO START HANDLING PROMISES, WHICH WOULD REQUIRE CHANGES ACROSS EVERYTHING. โ† WITH ALGEBRAIC EFFECTS, WE CAN SIMPLY STOP THE CURRENT PROCESS ALTOGETHER UNTIL OUR EFFECTS ARE FINISHED. EFFECT HANDLERS
  65. THE REACT TEAM APPARENTLY SPENT SOME TIME EXPERIMENTING WITH EFFECT-

    HANDLER CONTROL STRUCTURES FOR MANAGING LAYOUT
  66. function ThemeBorderColorRequest() { } function FancyBox(children) { const color =

    raise new ThemeBorderColorRequest(); return { borderWidth: '1px', borderColor: color, children: children }; } function BlueTheme(children) { return try { children(); } catch effect ThemeBorderColorRequest - > [, continuation] { continuation('blue'); } } function App(data) { return BlueTheme( FancyUserList.bind(null, data.users) ); }
  67. function ThemeBorderColorRequest() { } function FancyBox(children) { const color =

    raise new ThemeBorderColorRequest(); return { borderWidth: '1px', borderColor: color, children: children }; } function BlueTheme(children) { return try { children(); } catch effect ThemeBorderColorRequest - > [, continuation] { continuation('blue'); } } function App(data) { return BlueTheme( FancyUserList.bind(null, data.users) ); } THROW โ†’ RAISE CATCH โ†’ CATCH EFFECT
  68. HOOKS API โ† ALGEBRAIC EFFECTS = A SET OF OPERATIONS

    AND A SET OF EFFECT HANDLERS โ† THE OPERATIONS HERE ARE OUR HOOKS (E.G. useState, useEffect, AND SO ON) โ† WE HAVE TO SET UP HANDLERS IN EFF; IN REACT THEY'RE SET UP AS PART OF THE RENDER CYCLE
  69. HOOKS API โ† REACT IS RESPONSIBLE FOR MUCH OF THE

    IMPLEMENTATION OF WHEN/HOW OUR EFFECTS RUN โ† IT ALLOWS US TO STASH ENORMOUS AMOUNTS OF COMPLEXITY WITHIN REACT โ† BY SPLITTING EFFECTS AND RENDERING, WE ALLOW IT TO RELIEVE US OF SOME COMPLEXITY
  70. A COMPONENT IS ABLE TO SUSPEND THE FIBER IT IS

    RUNNING IN BY THROWING A PROMISE, WHICH IS CAUGHT AND HANDLED BY THE FRAMEWORK.
  71. A COMPONENT IS ABLE TO SUSPEND THE FIBER IT IS

    RUNNING IN BY THROWING A PROMISE, WHICH IS CAUGHT AND HANDLED BY THE FRAMEWORK. THROW โ†’ HANDLE โ†’ RESUME PATTERN.
  72. #QUOTE ๐Ÿค” โ€œAt my heart, I am something like the

    goto instruction; my creation sets the label, and my methods do the jump. However, this is a really powerful kind of goto instruction. [โ€ฆ]โ€ โ€”โ€‰GNU Smalltalk Continuation documentation
  73. โ† ITโ€™S AN ABSTRACTION THAT REPRESENTS THE REMAINING STEPS IN

    A COMPUTATION, AFTER WHERE WE PERFORM AN EFFECT. โ† IT'S A CONTROL FLOW PRIMITIVE. โ† DIFFERENT FROM goto. ALL THE VARIABLES, POINTERS, ETC. ARE VALID. CONTINUATIONS
  74. function performWork(deadline) { while (tasks.length > 0) { const task

    = tasks.shift(); doTask(task); if ( tasks.length > 0 & & !deadline.didTimeout & & deadline.timeRemaining() < = 0 ) { return performWork; } } } scheduleWork(performWork); CONTINUATIONS IN REACT
  75. โ† IT HANDLES A QUEUE OF TASKS IN A WHILE

    LOOP โ† IF THERE ARE STILL TASKS ON THE QUEUE, IT RETURNS performWork AND SCHEDULE IT FOR RESUMPTION AT SOME LATER TIME โ† IN THIS CONTEXT, IT REPRESENTS THE CONTINUATION OF A QUEUE OF TASKS CONTINUATIONS IN REACT
  76. async function doWork() { while (true) { let hasMoreWork =

    doSomeWork(); if (!hasMoreWork) { return; } if (!navigator.scheduling.isInputPending()) { continue; } await scheduler.yield(); } } ๐Ÿคฏ CONTINUATIONS ON THE WEB
  77. #1 REACT FIBER WAS A REWRITE OF REACT FOCUSED ON

    GIVING MORE LOW-LEVEL CONTROL OVER PROGRAM EXECUTION THE COMPUTER SCIENCE OF FIBERS
  78. #1 THE COMPUTER SCIENCE OF FIBERS โ† FIBERS AS A

    LOW-LEVEL COOPERATIVE WAY TO MODEL EXECUTION โ† ALGEBRAIC EFFECTS AS A WAY TO HANDLE EFFECTS WHERE THESE AND THEIR BEHAVIOR ARE INDEPENDENT EXECUTION
  79. #2 THE COMPUTER SCIENCE OF FIBERS REACT TRIES TO ADDRESS

    THE LACK OF SOME JAVASCRIPT FEATURES/ LANGUAGE-LEVEL RESOURCES BY IMPLEMENTING SOME ALTERNATIVE SOLUTIONS TO ACHIEVE SIMILAR BEHAVIORS E.G. EFFECT HANDLERS & CONTINUATIONS
  80. #3 THE COMPUTER SCIENCE OF FIBERS UNDERSTANDING SOME OF THESE

    CONCEPTS GIVES US A BETTER MENTAL MODEL FOR WHAT SOME REACT FEATURES ARE DOING BEHIND THE SCENES E.G. HOOKS AND EFFECT HANDLERS
  81. #4 THE COMPUTER SCIENCE OF FIBERS UNDERSTANDING THESE INTERNALS AND

    THEIR RATIONALES HELPS US IMPLEMENT OUR OWN ABSTRACTIONS E.G. THE COROUTINES-BASED SCHEDULER & THE PATTERN MATCHING COMPONENTS
  82. #5 THE FACT WE'RE DISCUSSING ALL OF THESE TOPICS SHOWS

    THAT REACT ACTS AS A DEMOCRATIC AGENT FOR THIS KIND OF KNOWLEDGE IN THE FRONT-END WORLD THE COMPUTER SCIENCE OF FIBERS
  83. THATโ€™S ALL, FOLKS! THANKS! ๐Ÿ‘‹ ๐Ÿ‡ฎ๐Ÿ‡ณ QUESTIONS? MATHEUS ALBUQUERQUE โ€ข

    @ythecombinator โ†‘ ALL THE LINKS! ๐Ÿค“ THE COMPUTER SCIENCE OF FIBERS