5 ms·
Can't speak for the grandparent, but for me, my beef basically boils down to one thing. When you use a stateful hook, there has to be some concept of identity
by recursive 4y ago
Can't speak for the grandparent, but for me, my beef basically boils down to one thing. When you use a stateful hook, there has to be some concept of identity of the calling component. You don't want to get someone else's state back when you call useState(). However, I've never seen it documented what actual process is used to determine the identity of a calling component. In fact, it is something that I've had problem with before.
Related, I don't feel comfortable giving up control of when a real DOM element is replace by a new instance. For some things, like canvas, file inputs, audio tags, this replacement needs to be carefully controlled or prevented. This seems to violate the react philosophy.
- 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
- charcircuit 4y ago>However, I've never seen it documented what actual process is used to determine the identity of a calling component. The first caller gets the first state, the second caller gets the second state, etc.
- recursive 4y agoClearly, there has to be more to it than that. Whole subtrees of the virtual DOM can (in some circumstances) be removed without affecting the states of the subsequent components. I'm not totally sure what the rules are for this, but at least sometimes it works.
- unconed 4y agoIt's not some big mystery and it's documented just fine. If you have a normal chunk of static jsx, child "i" maps to slot "i". If you wish to omit a child dynamically, you put a null in its place. If you have an array of children being built dynamically, every child needs an explicit key. This avoids state being shifted up and down needlessly when you add/remove. You will never get another component's state back because changing the type forces a remount. Unlike React, Live has the ability to preserve children even if the parent type changes (a morph), but this is opt-in only and will still discard the state of the parent.
- pygy_ 4y agoBy default, identity is the place in the vDOM tree (taking `null` nodes into account so that you can have conditional nodes in fragments/children lists). In lists, identity can instead be tracked by a user-provided key: https://reactjs.org/docs/lists-and-keys.html https://reactjs.org/docs/lists-and-keys.html