The article seems to use a state hooks implementation of the general Lifting State Up pattern to share state with a nested component (if so, a reference/link would be nice - mainly because mentioning "Lifting State Up" gives the approach a name - long before it can reveal itself through the details).
Side note:
The established term "child component" as it is used in this article is at best ambiguous, at worse misleading.
A parent component has its children passed via props.children - so a child component is the ReactNode (or an item in ReactNode[]) in props.children. The parent doesn't create its children but is composed with them.
The React documentation once used to contain the following:
It's important to draw a distinction between the owner-ownee relationship and the parent-child relationship. The owner-ownee relationship is specific to React, while the parent-child relationship is simply the one you know and love from the DOM.
Avatar is the owner (that sets the props) of ProfilePic and ProfileLink.
The <div> is the parent (but not the owner) of ProfilePic and ProfileLink.
Both ProfilePic and ProfileLink are children to <div> but are ownees of Avatar.
Using that terminology: "Passing Data from Ownee to Owner with React Hooks".
To use this with props.children the parent would likely have to use cloneElement to inject its update function into a component prop to create instances that interact with its state (though it probably makes more sense to use a render prop at that point).
I can only guess why "owner-ownee" was removed from the documentation - maybe they just gave up as everybody keeps using "parent-child" for the "owner-ownee" relationship.
Maybe the term "ownee" was a problem.
The Svelte documentation refers to components that are referenced in the markup section as nested components (child components go into the parent component's <slot></slot>).
Hello, and thanks for the reply! I wasn't aware of the owner/ownee terminology as it seems like I've read other people misusing parent/child before as well. You mention that the React documentation used to contain that distinction. Do you think it was removed because the terminology became so misused that parent/child functionally became used to mean both definitions?
I think the biggest issue here is that owner/ownee almost never matters, so it is awkward to mention in the introductory text.
This is a curious statement given how often parent/child is being used in introductory tutorials to describe the relationship between a component and the components being used in its render method - most often attempting to state something like:
"Passing props is how information flows in React apps, from owners to ownees."
So it would seem that the official documentation simply tries to avoid the parent/child terminology unless it's referring to a relationship within the render result (i.e. the DOM tree or some intermediate representation thereof).
"Passing props is how information flows in React apps, from parents to children."
In the absence of definitive terminology (i.e. avoiding owner/ownee) it's easy to think of the component that creates another component (while rendering) as the "parent".
The "component tree" could be seen as a hierarchy that represents the rendering process but that is different from the result of the rendering process - the "tree of rendered elements".
It is possible to imagine the "tree of rendered elements" and draw boxes around the fragments that are rendered by specific components - at that point a component could be perceived as "containing" elements or nested components.
It could also be argued that the "parent-child relationship between nodes" isn't all that interesting in React due to the limitations of the children prop. While children can be used to pass slotted content to a parent component, children needs to be a "children as a function" for the more interesting cases. But in those cases best practice suggests to use render props/component injection - which lessens the importance of children (and by extension the parent-child relationship).
import{createElementash,render,Component}from'https://unpkg.com/preact?module';// 1. In order to emulate a 'scoped slot'// the `children` prop has to be a// render prop so that the `MyList`// component can pass props to its `children`.//functionMyList({title,items,children}){return(h('section',{class:'my-list'},h('h1',null,title),h('ul',null,...items.map(item=>h('li',{class:'my-list__item'},children(item)// (1.))))));}// Given that the slot content// needs to receive props// the content needs to be// implemented as a component// (`Shape` and `Color`)functionShape({shape}){return(h('div',null,`${shape.name} `,h('small',null,`(${shape.sides} sides)`)));}functionColor({color}){return(h('div',null,h('div',{class:'swatch',style:`background: ${color.hex}`}),color.name));}// 2. Here `MyList` is parent to `Shape`// but as `MyList` needs pass props to `Shape`// `children` to `MyList` needs to be function.// 3. Similarly the `Color``children` to `MyList`// has to be a function.//functionApp({data}){return[h(MyList,{title:'Shapes',items:data.shapes},shape=>h(Shape,{shape})// (2.)),h(MyList,{title:'Colors',items:data.colors},color=>h(Color,{color})// (3.)),];}constdata={shapes:[{name:'Square',sides:4},{name:'Hexagon',sides:6},{name:'Triangle',sides:3},],colors:[{name:'Yellow',hex:'#F4D03F'},{name:'Green',hex:'#229954'},{name:'Purple',hex:'#9B59B6'},],};render(h(App,{data}),document.getElementById('app'));
Note that in the above example MyListis the parent of Shape (and Color) within the App component. But both Shape and Color have to be passed as "children as a function" (rather than simple child components) so that MyList can pass props to them. However typically this would be implemented with component injection - so the injected component is a simple prop rather than a child.
// 1. Here the 'scoped slot' is emulated with component injection:// - the `render` prop references the component to use// - the `name` prop identifies the prop name the// item should be passed by.//functionMyList({title,items,name,render:View}){return(h('section',{class:'my-list'},h('h1',null,title),h('ul',null,...items.map(item=>h('li',{class:'my-list__item'},h(View,{[name]:item})// (1.))))));}// ...// The `App` component using component injection instead//// 2. The `Shape` component is injected for rendering// while the `item` should be passed via the `shape` prop.// 3. The `Color` component is injected for rendering// while the `item` should be passed via the `color` prop.//// In effect the "slot content" is no longer passed as "children"//functionApp({data}){return[h(MyList,{title:'Shapes',items:data.shapes,name:'shape',render:Shape}),// (2.)h(MyList,{title:'Colors',items:data.colors,name:'color',render:Color})// (3.)];}
A "parent" is simply an element (or component) with an opening and closing tag (in JSX) and any elements (or components) between those tags are the "children" to that parent. The only time that relationship is really of any interest is with components with a slot:
the component with the slot is the "parent"
the content placed into the slot is the "child" (or children).
Using parent/child to also refer to the creational relationships between components can make discussions ambiguous and downright difficult when it is necessary to simultaneously discuss relationships within the creational (i.e. rendering) process and within the content model (e.g. DOM tree and the like).
The article seems to use a state hooks implementation of the general Lifting State Up pattern to share state with a nested component (if so, a reference/link would be nice - mainly because mentioning "Lifting State Up" gives the approach a name - long before it can reveal itself through the details).
Side note:
The established term "child component" as it is used in this article is at best ambiguous, at worse misleading.
A parent component has its children passed via
props.children
- so a child component is theReactNode
(or an item inReactNode[]
) inprops.children
. The parent doesn't create its children but is composed with them.The React documentation once used to contain the following:
Ownership:
So given:
Avatar
is the owner (that sets the props) ofProfilePic
andProfileLink
.<div>
is the parent (but not the owner) ofProfilePic
andProfileLink
.ProfilePic
andProfileLink
are children to<div>
but are ownees ofAvatar
.Using that terminology: "Passing Data from Ownee to Owner with React Hooks".
To use this with
props.children
the parent would likely have to usecloneElement
to inject its update function into a component prop to create instances that interact with its state (though it probably makes more sense to use a render prop at that point).I can only guess why "owner-ownee" was removed from the documentation - maybe they just gave up as everybody keeps using "parent-child" for the "owner-ownee" relationship.
Maybe the term "ownee" was a problem.
The Svelte documentation refers to components that are referenced in the markup section as nested components (child components go into the parent component's
<slot></slot>
).Hello, and thanks for the reply! I wasn't aware of the owner/ownee terminology as it seems like I've read other people misusing parent/child before as well. You mention that the React documentation used to contain that distinction. Do you think it was removed because the terminology became so misused that parent/child functionally became used to mean both definitions?
From Wrong context warning? - 'Warning: owner-based and parent-based contexts differ' #3451
According to Documentation inconsistencies around Parent/Child vs Owner/Ownee #7794
This is a curious statement given how often parent/child is being used in introductory tutorials to describe the relationship between a component and the components being used in its
render
method - most often attempting to state something like:"Passing props is how information flows in React apps, from owners to ownees."
So it would seem that the official documentation simply tries to avoid the parent/child terminology unless it's referring to a relationship within the render result (i.e. the DOM tree or some intermediate representation thereof).
React.createElement
So here it should be clear that
type
is the parent "node" tochildren
- but notice thattype
(the parent) doesn't createchildren
.However community contributions to the documentation may re-introduce the notion of the "creational parent":
"Passing props is how information flows in React apps, from parents to children."
In the absence of definitive terminology (i.e. avoiding owner/ownee) it's easy to think of the component that creates another component (while rendering) as the "parent".
The "component tree" could be seen as a hierarchy that represents the rendering process but that is different from the result of the rendering process - the "tree of rendered elements".
It is possible to imagine the "tree of rendered elements" and draw boxes around the fragments that are rendered by specific components - at that point a component could be perceived as "containing" elements or nested components.
It could also be argued that the "parent-child relationship between nodes" isn't all that interesting in React due to the limitations of the
children
prop. Whilechildren
can be used to pass slotted content to a parent component,children
needs to be a "children as a function
" for the more interesting cases. But in those cases best practice suggests to use render props/component injection - which lessens the importance ofchildren
(and by extension the parent-child relationship).Full gist
Note that in the above example
MyList
is the parent ofShape
(andColor
) within theApp
component. But bothShape
andColor
have to be passed as "children
as a function" (rather than simple child components) so thatMyList
can pass props to them. However typically this would be implemented with component injection - so the injected component is a simple prop rather than a child.A "parent" is simply an element (or component) with an opening and closing tag (in JSX) and any elements (or components) between those tags are the "children" to that parent. The only time that relationship is really of any interest is with components with a slot:
Using parent/child to also refer to the creational relationships between components can make discussions ambiguous and downright difficult when it is necessary to simultaneously discuss relationships within the creational (i.e. rendering) process and within the content model (e.g. DOM tree and the like).
Edit:
Another way to look at it - given:
CompA
is the parent toCompC
CompB
is the parent toCompD
App
toCompA
,CompB
,CompC
andCompD
.How does the statement:
"Passing props is how information flows in React apps, from parents to children."
hold up now?
CompA
toCompC
.CompB
toCompD
.App
.I guess:
CompA
andCompB
are parents from the content/document perspective.App
is a parent from the rendering perspective.But nobody seems to bother with that distinction.