5 ms·
> "not documented what the process is" It's fairly straightforward. React uses a module-scoped variable, assigns to it when it starts rendering a component, an
by acemarke 4y ago
> "not documented what the process is"
It's fairly straightforward. React uses a module-scoped variable, assigns to it when it starts rendering a component, and nulls it out when it's done rendering the component. Any other function in the hooks implementation file can then update that current "Fiber" object when the hook gets called by the component.
Shawn Swyx Wang has an excellent talk called "Getting Closure with React Hooks" where he builds a miniature version of this in about 20 minutes:
https://www.swyx.io/hooks/ https://www.swyx.io/hooks/
You can see the actual implementation in this file - I've highlighted that "current Fiber" variable:
https://github.com/facebook/react/blob/v18.0.0/packages/react-reconciler/src/ReactFiberHooks.new.js#L181-L187 https://github.com/facebook/react/blob/v18.0.0/packages/reac...
As for the "when a real DOM element is replaced" bit, _you_ have control over that. React will keep existing DOM nodes in place as long as you continue to tell it "render a node of this type in this spot in the tree". It only removes that DOM node when your render logic stops telling React it should exist (ie, a component is unmounted, or the component's render output changes and no longer includes that `<div>` or `<canvas>` or whatever type).
See my post "Guide to React Rendering Behavior" for some more details on this:
https://blog.isquaredsoftware.com/2020/05/blogged-answers-a-mostly-complete-guide-to-react-rendering-behavior/#component-types-and-reconciliation https://blog.isquaredsoftware.com/2020/05/blogged-answers-a-...
- recursive 4y ago> React will keep existing DOM nodes in place as long as you continue to tell it "render a node of this type in this spot in the tree" What exactly is a "spot in the tree"? If I need to keep an element, must I ensure that all prior elements, in DOM order, are kept in place? What if I want the stable element to be preceded by a conditionally rendered element? Is that supported by react? "UI is a function of state" sounds kind of cool, but in my mind "function of state" means that state is an input to the function, not acquired through back channels.
- acemarke 4y agoSay you have `<Parent>` and `<Child>`, and `<Child>` is outputting several HTML elements when it renders. There's three major aspects that control what happens to the DOM nodes that React created for `<Child>`: - If `<Parent>` stops rendering `<Child>`, React will completely unmount that `<Child>` instance, including removing all DOM nodes that were created for `<Child>` - If `<Child>`'s rendering logic noticeably changes the HTML elements it returned, like replacing a `<p>` with a `<div>` at that same spot in its tree of returned elements, React will remove the DOM nodes that are no longer needed. - If you identified specific child elements using the `key` prop, and you change the `key` you applied, React will take that as a signal to unmount the previous instance of that child and re-create it So, loosely put: React will keep the existing DOM nodes as long as you're still telling it you want elements of that type, at that depth and path in the tree of elements you return. So, sure, if you had something like `return <div>{condition ? <A /> : null}<B /></div>`, then React will keep that `<B>` instance alive, because you're continuing to ask for it in the same location. I'm not sure what you're trying to say with the "back channels" bit. Are you referring to how React manages hooks? React has _always_ kept the real props and state values stored in its internal data structures. In that sense, both class components and function components are just facades over how React actually stores things. In fact, even with class components, React would assign `componentInstance.props = theFiberObject.props` at the last second before rendering it. The fact that hooks tie into React's internal Fiber objects is just a different syntax for the behavior React always had. Per your other comment, it sounds like you are confused about how React rendering works. I'd _really_ encourage you to read my post that I linked above, which explains the general rules and behaviors. The behavior has also been described in the "Reconciliation" page in the React docs: https://reactjs.org/docs/reconciliation.html https://reactjs.org/docs/reconciliation.html
- recursive 4y agoThanks for the reading materials. I have read your post at least briefly. There's a lot to digest. The reconciliation docs covers a lot of my confusion. Here's what I mean by back channel. function fn(arg) { let foo = useFoo(); // do something with arg and foo } The way I understand the words, `fn` is a function of `arg`. `foo` was acquired by a "back channel".
- acemarke 4y agoI sorta see what you're saying, in that `foo` wasn't passed into this function as an argument. But I do still think this is a general misconception of how React works. Every React component, whether it's written as a class component or a function component, has props and optional state. In class components, those are accessed as `this.props` and `this.state`, which may seem "familiar" for folks who are used to OOP usage. But, as I note above, the fact that you can even access them as `this.something` is only because React itself has done the work to track those values in its internal `Fiber` structures, and assign them to the component fields when it's ready to render the component. For function components, it's the same thing, with slightly different syntax. Function components always get `props` as the one argument to the function. State, in the form of the `useState` and `useReducer` hooks, is accessed on-demand, but it's still coming from React's source of truth: the `Fiber` object that represents React's tracking of this component instance. I'll agree that it's not an _obvious_ argument to the component. But then again, neither is React Context, which is another source of input to components that isn't directly passed in as props either. That's my point - it's really all about React storing the data for a component internally, and then making that accessible to the component as needed while rendering.