React child reconciliation query - reactjs

I am reading React documentation and I have following two queries about child reconciliation.
Following link says that when children are deleted, instead of deleting them, they can be hidden with display set to 'none'. The specific sentence is:
"In most cases, this can be sidestepped by hiding elements instead of destroying them"
Who is supposed to sidestep? Does React do it automatically or does the programmer have to indicate to React framework to set display style to 'none' instead of reusing it?
(Link: https://facebook.github.io/react/docs/multiple-components.html#stateful-children)
Following link says that in case of reordered children, React can be informed to avoid unnecessary node deletes by assigning a key to each child. However, these keys should be assigned to the component and not to HTML container. But example before that shows assigning key to HTML container which is <li> in that case. What am I missing here?
(Link: https://facebook.github.io/react/docs/multiple-components.html#dynamic-children)

This is explicit on the part of the programmer. You should program the component to set a dynamic style to hide the element if you want this behavior, as per the example:
// Render Pass 1
<Card>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</Card>
// Render Pass 2
<Card>
<p style={{display: 'none'}}>Paragraph 1</p>
<p>Paragraph 2</p>
</Card>
You should put the key on the top-level element or component returned from the map function. In this example, it's the li:
{results.map(function(result) {
return <li key={result.id}>{result.text}</li>;
})}
In this example, it's the component that renders the li.
{this.props.results.map(function(result) {
return <ListItemWrapper key={result.id} data={result}/>;
})}

Related

component not updating - issue with how to use key

I have a card component that is used across the site. The card doesn't fully update when the data is updated, or if it changes to another card, it will sometimes retain information in the card, from the previous one. The information that isn't changing all the time, are the areas where it's being rendered from a function this.renderPrice(), this.renderPerks(), and this.renderButtons(). I've tried adding a key to the actual component, and when the component is being called from another component, but neither seem to solve the issue.
class ChooseMembershipCard extends React.Component {
return(
<div className="membership_card" key={this.props.product.id}>
<h6 className="membership_banner">{this.renderSpotsAvailable()}</h6>
<h6 className="membership_title">{this.props.product.title}</h6>
{this.renderPrice()}
<p className="membership_description">{this.props.product.description}</p>
{this.renderPerks()}
<div style={{padding: 10, marginTop: 20}}>
{this.renderButtons()}
</div>
</div>
)
export default ChooseMembershipCard
I am using in this component, where I've tried adding the key to the component, but it doesn't seem to make a difference
return (
<ChooseMembershipCard
key={this.state.products[this.state.selectedProductIndex]}
product={this.state.products[this.state.selectedProductIndex]}
isUser={this.state.isUser}
selectedProductIndex={this.state.selectedProductIndex}
monthlyFrequency={this.state.monthlyFrequency}
userHasSubscription={this.userHasSubscription}
loadUser={this.props.loadUser}
/>
)
And then I map through products here, and render a card for each one. When I update information inline, the data saves and is updated, but the actual component doesn't re-render, so the updated information is not seen unless the page is refreshed.
renderProducts() {
return this.state.products.map((product, i) => {
return (
<ChooseMembershipCard
key={product.id}
product={product}
isUser={true}
isEditable={true}
archiveProduct={this.archiveProduct}
editProduct={this.editProduct}
/>
)
})
}
In the above example, I always get 1 error:
ChooseMembershipCard: "key" is not a prop. Trying to access it will result in "undefined" being returned. If you need to access the same value within the child component, you should pass it as a different prop.
But if I remove the key, I then get this error:
Each child in a list should have a unique "key" prop.
I feel like the issue is how key is being used. Any insight is appreciated!
You are passing key into ChooseMembershipCard Component. Why dont you use the same key props while assigning into that div.
class ChooseMembershipCard extends React.Component {
return(
<div className="membership_card" key={this.props.key}>
<h6 className="membership_banner">{this.renderSpotsAvailable()}</h6>
<h6 className="membership_title">{this.props.product.title}</h6>
{this.renderPrice()}
<p className="membership_description">{this.props.product.description}</p>
{this.renderPerks()}
<div style={{padding: 10, marginTop: 20}}>
{this.renderButtons()}
</div>
</div>
)
export default ChooseMembershipCard
You need to add key to the component which is being rendered multiple times. In renderProducts() map function you are adding key prop but ur not actually assigning it into ChooseMembershipCard Component instead passing a prop named key to that Component and your not using it anywhere in your code.

How to get rid of 'key' error while using map in React?

Everyone know this error: Each child in a list should have a unique "key" prop But what if I have array of strings that I want to render in my paragraph with at the end?
return(
<p>
{array.map(string => {
return <>{string}<br/></>
})}
</p>
)
As you can see I'm literally returning only text with <br/> at the end, I don't have place or need for a key. How can I get rid of this error? Wrapping every phrase in <span> is not an option.
When React renders changes, before pushing changes to the DOM, it uses the virtual DOM to intelligently decide which changes it needs to push to keep things efficient, as DOM manipulation can be an expensive operation.
When rendering a collection of child elements, let's say some <li> elements, React will complain when a unique key prop has not been provided. The reason why it needs this prop is so it can perform the intelligent decision I mentioned above.
Oh and as #JBallin mentioned in the comments, you should define the key prop as a string, as it is not recommended to use the index for it:
return(
<p>
{array.map((string, index) => <React.Fragment key={index.toString()}>{string}<br/></React.Fragment>)}
</p>
);
you can use map index for key of paragraph like this:
return(
<p>
{array.map((string,index)=> {
return <React.fragment key={index}>{string}<br/></React.fragment>
})}
</p>
)

Can one React component render by 2 classes?

Can one React component render by 2 classes? Just like I did in the picture.
I tried the above. It gives me another error Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of "Groups".
The button component Im using in Groups method(Groups.jsx) like this way.
const Groups = (props) => (
<div className = 'panel'>
<h2>Groups</h2>
<button >Get Groups</button>
<div className = 'group-list'>
{props.groups.map((group) =>
<GroupsEntry name = {group.name}
members = {group.members}/>
)}
</div>
</div>
);
Do you guys have any idea about this? Thank you
I will try to clarify a little.
You can render a component from whatever parent component you want.
By in the case of your picture, what is telling you that the first component in tree, was App.js, and then App.js rendered Groups.js component, and Groups.js rendered your actual component.
In the same page, the warning you are seeing about using "key" is because you need to set a unique key value for each element that you are rendered as a list, a repeated item. This is because the internal react work to compare if it has to rerender again your component needs it. You will have performance problems (not in an easy example...) if you dont add it. Normally you use the id of the object you are rendering.
I hope i clarified a little.
Yes, a component can be rendered as many times as you would like. The issue is that you are mapping over an array and returning an element. React requires that you put a unique key prop on these elements that ideally are consistent between renders.
You can try to update your code to be something like the following:
const Groups = props => (
<div className="panel">
<h2>Groups</h2>
<button>Get Groups</button>
<div className="group-list">
{props.groups.map(group => (
<GroupsEntry key={group.name} name={group.name} members={group.members} />
))}
</div>
</div>
);
This is assuming group.name is unique. If you have a unique identifier (eg: group.id) that would be ideal.
For more examples and why this is necessary you can checkout the official docs: https://reactjs.org/docs/lists-and-keys.html

Twinkling images in a component

I have component with navigation, on click item to child component passed in props some params, one of params - object 'itemImage' with className and url, like this:
{
url: '/static/image.svg',
className: 'absolute hidden md:block min-w-53 lg:min-w-68 mt-30 lg:mt-19 -ml-28 lg:-ml-75',
}
In child component ItemComponent:
{
itemImage &&
<img className={itemImage.className} src={itemImage.url} alt='' />
}
ItemComponent is selected from an array according to the order of the element in navigation (it is responsible for the object passed to the child component), since the list of navigation elements and elements of the array of pictures are not related and of different lengths. The sample is implemented on the basis of an index in map for objects and an index in an array with pictures, to be more precise.
Problem:
the pictures flicker as the state of the parent and the child is updated, is it possible to somehow avoid this and make the change of the picture clear without the flickering of the previous card.
You can use the below-mentioned code to render the Array of Images.
<>
{this.props.Images.map(item=>{
return (item)
})}
<p>
{JSON.stringify(this.state)}
</p>
<p>
{JSON.stringify(this.props.changed)}
</p>
<button onClick={this.props.onChange}>Change</button>
<button onClick={this.onCurrentChange}>Current State Change</button>
</>
Please check the demo here Demo
You can make somethings to try to prevent that.
1- Add a key prop to the elements. It help react understand that it is the same data from before and not re-render that piece.
2- Use react PureComponent on the flickering element https://reactjs.org/docs/react-api.html#reactpurecomponent to prevent the re-render
3 - Instead of purecomponent implement shouldComponentUpdate

React pass children to sibling

I have run into a situation where it seems I need to pass the children of one component over to another that is a sibling of the original. This doesn't sit well with me as it seems to go against what I've learned is the proper hierarchy and communications channels in React. I need the components to render as siblings due to styling issues, but I'd like to have a logical grouping of components for developers utilising my component.
In short I have some buttons and some of these buttons display a drop-down menu. Like a toolbar of sorts. I want the menu to pop up in a modal like way and so I don't want to place a sub-div next to the button. Instead I want it to render below the buttons and just swap its components with whatever menu is currently active.
Here is how I envision the rendering to look:
<ul>
<li><button>Triggers some action elsewhere</button></li>
<li><button>Button with menu</button></li>
<li>Link</li>
<li><button>Button with menu</button></li>
<li><button>Triggers some action elsewhere</button></li>
</ul>
<div class="menu-container">
Menu content goes here
</div>
Since the buttons are 1-1 linked with a menu I want the developer to work with the components like this:
<Nav>
<NavButton text="Triggers some action elsewhere"/>
<NavMenu text="Button with menu">
<Link to="/">A link</Link>
<Box>
...
</Box>
</NavMenu>
<NavLink>
<Link to="/">Link</Link>
</NavLink>
<NavMenu text="Button with menu">
<Link to="/">A link</Link>
<Box>
...
</Box>
</NavMenu>
<NavButton text="Triggers some action elsewhere"/>
{/*
This component is dynamically inserted by <Nav/> at this position.
It is responsible for rendering a floating menu and controlling its
behaviour.
*/}
<FloatingMenu></FloatingMenu>
</Nav>
The <Nav> component would then swap the content of the .menu-container div based on whether a menu was open or not.
EDIT!
I forgot to mention that there is a separate component here that the developer doesn't see. The <FloatingMenu> component is dynamically inserted by <Nav> and not actually part of the set of children that the developer will write. It is responsible for rendering the actual menu div and controlling its behaviour. So what I'd like to do is move all children from the currently active <NavMenu/> component into the <FloatingMenu/> and empty it out if no menus are active. At least that was my original idea.
/EDIT!
Can this be done? Am I over complicating or misunderstanding something? Any help would be much appreciated!

Resources