Can one React component render by 2 classes? - reactjs

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

Related

Why infinite scroll pagination uses useState not using DOM append instead?

I have seen many tutorials and articles which use useState to store all the records on a state instead of using ReactDOM or something to add HTML elements.
For example, they keep previous data and merge with new data and after that set in a useState hook
return [...new Set([...prevBooks, ...res.data.docs.map(b => b.title)])]
I have 2 questions
Isn't it a performance problem to have all the records in the state and to print it in JSX by map? There may be millions of records.
If I want to add a React component to the end of a div#ID, what should we do in the pagination?
For example, I have this block code:
<article className="col-sm">
<div className="row client-home-header-post-article-row" id="BlogsPosts">
{posts.entries.map((item) => (
<BlogItem post={item} key={item.id} size={4} />
))}
</div>
</article>
And with an action function like const showMore, add another <BlogItem post={item} key={item.id} size={4} /> to the bottom of BlogsPosts ID (like e.append)
I saw this post Append component in React, he suggested without recommending to use ReactDOM.createPortal, but I tested it like this, and it does not work
ReactDOM.createPortal(
<BlogItem post={item} key={item.id} size={4} />,
document.querySelector("#BlogsPosts")!
)
The posts I saw:
Append component in React
Reactjs append an element instead of replacing
How do you append a React Component to an html element
How to append React components to HTML element using .append()
How can I append a React component to an html element i?
Using document.querySelector in React? Should I use refs instead? How?
Append Element to an Existing Element React
Thank you in advance
Isn't it a performance problem to have all the records in the state
and to print it in JSX by map? There may be millions of records.
It depends. A performant server should try to keep the metadata it returns to the browser for each book small. That is, each book object should try to to contain minimal information like a title, author, price, and thumbnail URL, not all the data that the database knows about the book. Something like this:
{
"title":"MyBook",
"author":"Jeff Bezos",
"price":19.99,
"price_unit":"USD",
"thumbnail":"https://websitename.s4-bucket.region.UUID-1234"
}
Reducing the amount of data will boost performance by making searching through this data faster on the browser. Each object of this size is also less than 500 bytes, so if you are obtaining 50 items at a time you're only retrieving 25KB data per request, which with modern speeds only takes a few milliseconds.
If I want to add a React component to the end of a div#ID, what should
we do in the pagination?
You can use a useMemo hook which will update the BlogItem components you have rendered when the posts change. Something like this should work:
const blogItems = useMemo(()=>posts.entries.map((item) => (
<BlogItem post={item} key={item.id} size={4} />
)), [posts.length])
Then in your JSX just do this:
<article className="col-sm">
<div className="row client-home-header-post-article-row" id="BlogsPosts">
{blogItems}
</div>
</article>

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>
)

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

When should I be using React.cloneElement vs this.props.children?

I am still a noob at React and in many examples on the internet, I see this variation in rendering child elements which I find confusing. Normally I see this:
class Users extends React.Component {
render() {
return (
<div>
<h2>Users</h2>
{this.props.children}
</div>
)
}
}
But then I see an example like this:
<ReactCSSTransitionGroup
component="div"
transitionName="example"
transitionEnterTimeout={500}
transitionLeaveTimeout={500}
>
{React.cloneElement(this.props.children, {
key: this.props.location.pathname
})}
</ReactCSSTransitionGroup>
Now I understand the api but the docs don't exactly make clear when I should be using it.
So what does one do which the other can't? Could someone explain this to me with better examples?
props.children isn't the actual children; It is the descriptor of the children. So you don't have actually anything to change; you can't change any props, or edit any functionality; you can only read from it. If you need to make any modifications you have to create new elements using React.CloneElement.
https://egghead.io/lessons/react-use-react-cloneelement-to-extend-functionality-of-children-components
An example:
main render function of a component such as App.js:
render() {
return(
<Paragraph>
<Sentence>First</Sentence>
<Sentence>Second</Sentence>
<Sentence>Third</Sentence>
</Paragraph>
)
}
now let's say you need to add an onClick to each child of Paragraph; so in your Paragraph.js you can do:
render() {
return (
<div>
{React.Children.map(this.props.children, child => {
return React.cloneElement(child, {
onClick: this.props.onClick })
})}
</div>
)
}
then simply you can do this:
render() {
return(
<Paragraph onClick={this.onClick}>
<Sentence>First</Sentence>
<Sentence>Second</Sentence>
<Sentence>Third</Sentence>
</Paragraph>
)
}
Note: the React.Children.map function will only see the top level elements, it does not see any of the things that those elements render; meaning that you are providing the direct props to children (here the <Sentence /> elements). If you need the props to be passed down further, let's say you will have a <div></div> inside one of the <Sentence /> elements that wants to use the onClick prop then in that case you can use the Context API to do it. Make the Paragraph the provider and the Sentence elements as consumer.
Edit:
Look at Vennesa's answer instead, which is a better explanation.
Original:
First of all, the React.cloneElement example only works if your child is a single React element.
For almost everything {this.props.children} is the one you want.
Cloning is useful in some more advanced scenarios, where a parent sends in an element and the child component needs to change some props on that element or add things like ref for accessing the actual DOM element.
In the example above, the parent which gives the child does not know about the key requirement for the component, therefore it creates a copy of the element it is given and adds a key based on some unique identifier in the object. For more info on what key does: https://facebook.github.io/react/docs/multiple-components.html
In fact, React.cloneElement is not strictly associated with this.props.children.
It's useful whenever you need to clone react elements(PropTypes.element) to add/override props, without wanting the parent to have knowledge about those component internals(e.g, attaching event handlers or assigning key/ref attributes).
Also react elements are immutable.
React.cloneElement( element, [props], [...children] ) is almost equivalent to:
<element.type {...element.props} {...props}>{children}</element.type>
However, the children prop in React is especially used for containment (aka composition), pairing with React.Children API and React.cloneElement, component that uses props.children can handle more logic(e.g., state transitions, events, DOM measurements etc) internally while yielding the rendering part to wherever it's used, React Router <switch/> or compound component <select/> are some great examples.
One last thing that worth mentioning is that react elements are not restricted to props.children.
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
function App() {
return (
<SplitPane
left={
<Contacts />
}
right={
<Chat />
} />
);
}
They can be whatever props that makes sense, the key was to define a good contract for the component, so that the consumers of it can be decoupled from the underlying implementation details, regardless whether it's using React.Children, React.cloneElement, or even React.createContext.

Resources