Child state updated but not rendering [duplicate] - javascript

This question already has answers here:
map is not rendering the ui elements in reactjs
(2 answers)
Closed 2 years ago.
I have a child component named Recently Opened. There are no props passed to the child component from parent component. The rendor method of parent component is:
render() {
return (
<div>
<RecentlyOpened />
</div>
);
}
The render method of child component(RecentlyOpened) looks like this:
render() {
return (
<div className='outer-box'>
{this.state.items.map(item => {
<div className='item-box'>
<img className='image' src={'/src/assets/' + item.imgURL} />
<div className='name item-margin'>{item.name}</div>
<div className='id item-margin'><b>SKU/ID: </b>{item.productId}</div>
</div>;
})}
</div >
);
}
Here this.state.items is populated from an API call. But even as the state is updated(I have checked this) after the API call returns the data, the UI inside the map function doesn't get displayed and just the empty div is rendered. Shouldn't the UI be updated once the state of child component changes?

You are not returning a value in your map loop. A simple fix is to replace the curly brackets with parentheses.
render() {
return (
<div className='outer-box'>
{this.state.items.map(item => (
<div className='item-box'>
<img className='image' src={'/src/assets/' + item.imgURL} />
<div className='name item-margin'>{item.name}</div>
<div className='id item-margin'><b>SKU/ID: </b>{item.productId}</div>
</div>;
))}
</div >
);
}

Related

Each child in a list should have a unique "key" prop Reactjs

I am working on Nextjs/Reactjs i am fetching data after click on button but in my console i am getting following error
Each child in a list should have a unique "key" prop
Here is my current code ( data is displaying with id and title)(
<button onClick={fetchReviewsFromServer}>Load Reviews From Server</button>
{
reviewfromserver.map(reviewnew=>{
return(
<>
<div key={reviewnew.id}> // not working
<div>{reviewnew.id}- {reviewnew.title} </div>
</div>
</>
)
})
}
The child in your list is the empty <> element, I don't see a need for it regardless, since you only have one child element to that element.
<button onClick={fetchReviewsFromServer}>Load Reviews From Server</button>
{
reviewfromserver.map(reviewnew=>{
return(
<div key={reviewnew.id}> // not working
<div>{reviewnew.id}- {reviewnew.title} </div>
</div>
)
})
}
That's because the fragmets are items. Remove them, you don't need them anyway.

Get key of mapped child component from parent function

I have a child navigation component and i'm trying to get the key of the selected item in the parent component to update my state to the selected nav item. I'm using a map in the child component and I cant seem to pass the key of the selected item back up to the parent item to set the state. here are my components
Parent
** my function to set the nav item **
let navPress = async key => {
let selNavItem = await navItems.find(object => {
return object.key === key
});
setActiveNavItem(selNavItem.key)
}
** return for parent component **
return(
<ProjectDetailNav
navItems={navItems}
activeNavItem={activeNavItem}
onClick={() => navPress}
/>
)
Child component (nav) with map function
<div id='nav-container'>
{props.navItems.map(navItem => {
if (navItem.key === props.activeNavItem) {
// console.log(navItem.key)
return (
<button className='active-nav-item' key={navItem.key} onClick={props.onClick(navItem.key)}>
<img className='nav-item-icon' src={navItem.icon} />
<h6 className='nav-item-title'>{navItem.title}</h6>
</button>
)
} else {
return (
<button className='nav-item' key={navItem.key} onClick={props.onClick(navItem.key)}>
<img className='nav-item-icon' src={navItem.icon} />
<h6 className='nav-item-title'>{navItem.title}</h6>
</button>
)
}
})}
</div >
By onClick={props.onClick(navItem.key)} you are assigning the return value of props.onClick to buttons click event calling it immediately on render. It should be wrapped in a function.
<button
className="active-nav-item"
key={navItem.key}
onClick={() => props.onClick(navItem.key)}
>
<img className="nav-item-icon" src={navItem.icon} />
<h6 className="nav-item-title">{navItem.title}</h6>
</button>
This way when onClick event is fired, the anonymous function will be called which will call props.onClick(navItem.key).

How to manipulate child's render output

I'm using a component form a third party library and I want to manipulate the render output.
Let's say we have two components:
// third party component that I don't have access to its code
const ThirdPartyComponent = () => (
<div>
<span>
...
</span>
</div>
)
// My component using the third party component
const MyComponent = () => (
<div className="wrapper">
<ThirdPartyComponent />
</div>
)
Normally the output will be:
<div class="wrapper">
<div>
<span>
...
</span>
</div>
</div>
Now I want to manipulate the third party component such that my component renders this:
<div class="wrapper">
<span>
...
</span>
</div>
Or in other words unwrap the rendered content from an unwanted <div /> element.
1. I can't change the third party code
2. The child component doesn't forward ref
Any idea how to do this? 🤔
If:
the third party component is a function component, and
the third party component does not use refs (or if you're careful), and
you don't mind losing the component boundary for ThirdPartyComponent (essentially MyComponent will "be" ThirdPartyComponent), and
you solemnly swear you understand this might break in the future
you can call the component as if it was a function, then dig into the returned JSX object and get the first child, á la:
const ThirdPartyComponent = () => (
<div style={{border: "1px solid orange"}}>
<span>...</span>
</div>
);
const MyComponent = () => {
const thirdPartyDiv = ThirdPartyComponent(); // This is naughty!
const span = thirdPartyDiv.props.children; // The child is the span
return (
<div className="wrapper">
{span}
</div>
);
}
Alternately, if all you're doing is re-wrap the component, you could modify thirdPartyDiv.props.className to suit your needs...
const MyComponent = () => {
const thirdPartyDiv = ThirdPartyComponent(); // This is naughty!
thirdPartyDiv.props.className = "wrapper";
return thirdPartyDiv;
}

Appending a new dom element in react

I've created a custom component and I want to add child element when the component renders if a certain property is set to be true. I used the following code, but the component is not rendered. what am I doing wrong here.
let deleteNode = '';
if(deletable){
deleteNode = '<div />'
}
let defaultClasses = 'chips chips-rounded';
return (
<div className={classNames(classes, defaultClasses)} onClick={ this.onClick }>
{avatar}
<span>{this.props.labelText}</span>
{deleteNode}
</div>
)
You are trying to render a component but actually you are just sending string in your deleteNode. Your code should be something like below
if(deletable){
deleteNode = (<div />);
}
I different approach would be:
render() {
const defaultClasses = 'chips chips-rounded'
return (
<div className={classNames(classes, defaultClasses)} onClick={ this.onClick }>
{avatar}
<span>{this.props.labelText}</span>
{deletable && <div />}
</div>
)
}
So you don't need the extra if checking.

React component with two sets of children

I'm creating a component that needs to take in two sets of children and to be placed in two different parts of a component.
let CreditCardForm = ({icons, fields}) => (
<div>
<div className='some'>
<div className='special'>
<div className='nesting'>
{icons}
</div>
</div>
</div>
{fields}
</div>
)
let CreditCardFormUsage = () => {
let icons = () => (
<Icons>
<IconBogus/>
<IconVisa/>
<IconPaypal/>
<IconMore/>
</Icons>
)
let fields = () => (
<CreditCardFields>
<FieldCardNumber/>
<FieldName/>
<FieldExpirey/>
<FieldCCV/>
</CreditCardFields>
)
return (
<CreditCardForm icons={icons} fields={fields}/>
)
}
The code above should work, my question is it possible to grab those property values based on the children in the element itself, and have something more natural?
<CreditCardForm>
<Icons>
<IconBogus/>
<IconVisa/>
<IconPaypal/>
<IconMore/>
</Icons>
<CreditCardFields>
<FieldCardNumber/>
<FieldName/>
<FieldExpirey/>
<FieldCCV/>
</CreditCardFields>
</CreditCardForm>
Yes, this.props.children will return an array so if you always want to load specific children, then just reference those children by index in your wrapper. Then you could just turn icons and fields into wrapper components. Here is a working jsfiddle. See how the render method of App is exactly what you want.
CreditCardForm render:
<div>
<div className='some'>
<div className='special'>
<div className='nesting'>
{this.props.children[0]}
</div>
</div>
</div>
{this.props.children[1]}
</div>
Fields and Icons render:
<div>{this.props.children}</div>
App render:
<CreditCardForm>
<Icons>
<IconBogus />
</Icons>
<Fields>
<FieldCardNumber />
<FieldName />
</Fields>
</CreditCardForm>
yes, you can do it with child props. Read more #docs:
https://facebook.github.io/react/tips/children-props-type.html
And of course check out React.Children
https://facebook.github.io/react/docs/top-level-api.html#react.children

Categories

Resources