How to return React component inside mapping - reactjs

I just can't figure out the syntax mistake here, but my React components won't render. What am I doing wrong?
return (
shouldShow && (
<div>
{this.props.photos.map(({ url }) => {
return (
this.state.expanded
? <ImageGallery passedProp={url} />
: <AnotherComponent passedProp={url}
)
})}
</div>
)
);
I get the error:
JSX attributes must only be assigned a non-empty expression
EDIT updated full code as requested:
showGallery = () => {
const shouldShow = this.props.photos.length > 0;
return (
shouldShow && (
<div>
{this.props.photos.map(({ url }) => {
return (
this.state.expandedThumbnail
? <ImageGallery imageUrl={urlurlurl}/>
: <button
key={url}
onClick={this.doThis}
>
<img
src={url}
/>
</button>
)
})}
</div>
)
);
};

Related

Trying to show element based on user selection

Here I have my div that contains Two Options ["Book" , "prices"] .
My goal is when the user select the Book option it would show the element for the book , same thing for the price one too .
here is my code :
const BooksandPrices = props => {
const option =["Book" , "Prices"]
return (
<div>
{option.map((option) => (
<div
className='bp'
onClick={(e) => {
{option == 'Book' && <PriceTable />}
{option == 'Prices' && <BookTable />}
}}
>
{option}
</div>
))}
</div>
)
}
return (
<BooksandPrices />
)
If my presumption is correct that and are the elements for each respective option, then you'll want to move them outside of the option.map and initialize a state variable to control which element is displayed
const BooksandPrices = props => {
const [selectedOption, setSelectedOption] = useState();
const option =["Book" , "Prices"]
return (
<div>
{option.map((option) => (
<div
className='bp'
onClick={() => setSelectedOption(option)}
>
{option}
</div>
))}
{selectedOption == 'Book' && <PriceTable />}
{selectedOption == 'Prices' && <BookTable />}
</div>
)
}
return (
<BooksandPrices />
)
React Hooks could solve this, you just need to add useState hook.
Also keep in mind that you should to add key attribute when you loop through an array.
const BooksandPrices = props => {
const option =["Book" , "Prices"];
const [checkedOption, setCheckedOption] = useState("Book");
return (
<div>
{option.map((option, idx) => (
<div
className='bp'
onClick={()=>setCheckedOption(option)}
key={idx}
>
{option}
</div>
))}
<div>
{checkedOption === 'Book' ? <BookTable />:<PriceTable /> }
</div>
</div>
)
}

Where is the missing key for my child comp?

I've been getting a "Each child in a list should have a unique key prop" error. I've read up on the documentation and put keys in, but no luck. Not sure what I'm misunderstanding!
blogPosts is imported from a context.
The ids being called as keys are unique (POSTID1, POSTID2, ...etc).
Got rid of some classnames for better readability.
const topicPosts = blogPosts.filter((post)=>post.topic.toLowerCase()===topic);
const handleLoadMore = () => {
const newIndex = articleIndex + 5 > topicPosts.length ? topicPosts.length : articleIndex + 5;
setArticleIndex(newIndex);
}
return (
<section onClick={handleOutsideClick}>
<div>
<section>
<h1>{topic}</h1>
{
topicsData.map((topicData)=> topicData.name.toLowerCase()===topic && <p key={topicData.id}>{topicData.intro}</p>)
}
</section>
<div>
<section>
<div>
{
topicPosts.slice(0,3).map((post)=>{
const { id } = post;
return (
<TopicPagePost key={id} {...post}/>
)
})
}
</div>
<div className={topicPosts.length>3 ? `subpage-articles` : `display-none`}>
{
topicPosts.slice(3,articleIndex).map((post, index)=>{
const { id } = post;
return (
<>
<TopicPagePost key={id} {...post}/>
{
index%4===0 && <div key={index} className="subpage-main-ad">
Ad placement here
</div>
}
</>
)
})
}
</div>
<button type="button" onClick={handleLoadMore}>Load more articles</button>
</section>
<aside>
<SubscribeBlock/>
<div>
Ad placement here
</div>
</aside>
</div>
</div>
</section>
)
That is because you need to add a key to the first element returned from the map, in this case <>.
To do that, you need to replace <> with a <Fragment> instead, so you can add a key directly to it:
import React, { Fragment } from "react"
{topicPosts.slice(3,articleIndex).map((post, index) => {
const { id } = post;
return (
<Fragment key={id}>
<TopicPagePost {...post}/>
{index%4===0 && (
<div className="subpage-main-ad">
Ad placement here
</div>
)}
</Fragment>
)
})}

while using map() function props.data is undefined

its shows data without map function in console
but whenever I use map function it shows props.data is undifned and also undifined in console
I have used the same code for another page and that works
const Test_Footer = (props) => {
console.log("ok", props.data)
const newvar =props.data.map((item) => {
return (
<>
<li>{item.data.id}</li>
</>
)
})
// console.log(newvar)
return (
<div>
<div class="main-content">
<footer className="footer">
<div className="review-checkbox"><input type="checkbox" /><label>Review</label></div>
<div className="question-nav">
<ul className="pagination">
{newvar}
</ul>
<button className="minimize-btn ml-10"><img src="images/minimize-btn.png" /></button>
</div>
</footer>
</div>
</div >
)
}
export default Test_Footer
const newvar = props && props.data && props.data.map((item) => {
return (
<>
<li>{item.data.id}</li>
</>
)
})

React child not re-rendered when parents props change

I'm having some issues with child re-rendering, I pass methods to children to see if a button should be displayed or not but when the state of the parent changes, the children are not re-rendered.
I tried with the disabled attribute for the button but didn't work either.
Here's my code (I removed unnecessary part):
function Cards(props) {
const isCardInDeck = (translationKey) => {
return props.deck.some(
(card) => !!card && card.translationKey === translationKey
);
};
const addToDeck = (card) => {
if (!isCardInDeck(card.translationKey) && !!card) {
props.deck.push(card);
}
};
const removeFromDeck = (card) => {
if (isCardInDeck(card.translationKey) && !!card) {
var index = props.deck.findIndex(
(c) => c.translationKey === card.translationKey
);
props.deck.splice(index, 1);
}
};
return (
<div className="cardsContent">
<div className="cards">
{cardList.length > 0 ? (
cardList.map((item, index) => {
return (
<Card key={index} card={item} addToDeckDisabled={isCardInDeck(item.translationKey)} addToDeckClick={addToDeck} removeFromDeckClick={removeFromDeck} />
);
})
) : (
<span>
<FormattedMessage id="app.cards.label.no.card.found" defaultMessage="No card found with filter."/>
</span>
)}
</div>
</div>
);
}
function Card(props) {
const toggleShowDescription = () => {
if (!showDescription) {
setShowDescription(!showDescription);
}
};
return (
<div onClick={toggleShowDescription} onBlur={toggleShowDescription} >
<img src={"../images/cards/" + props.card.image} alt={props.card.image + " not found"} />
{showDescription ? (
<div className="customCardDetail">
<div className="cardName"></div>
<div className="cardType">
{props.addToDeckDisabled ? (
<Button onClick={() => { props.removeFromDeckClick(props.card);}} startIcon={<RemoveIcon />}>
Remove from deck
</Button>
) : (
<Button onClick={() => { props.addToDeckClick(props.card); }} startIcon={<AddIcon />}>
Add to deck
</Button>
)}
</div>
<div className="cardDescription">
<span>
<FormattedMessage id={props.card.description} defaultMessage={props.card.description} />
</span>
</div>
</div>
) : (
""
)}
</div>
);
}
You code does not update state. Cards mutates the props that it is receiving.
To use state in a functional component in React you should use the useState hook.
Cards would then look something like this:
function Cards(props) {
const [deck, setDeck] = useState(props.initialDeck)
const isCardInDeck = (translationKey) => {
return deck.some(
(card) => !!card && card.translationKey === translationKey
);
};
const addToDeck = (card) => {
if (!isCardInDeck(card.translationKey) && !!card) {
setDeck([...deck, card])
}
};
const removeFromDeck = (card) => {
if (isCardInDeck(card.translationKey) && !!card) {
setDeck(deck.filter(deckItem => deckItem.translationKey !== card.translationKey))
}
};
return (
<div className="cardsContent">
<div className="cards">
{cardList.length > 0 ? (
cardList.map((item, index) => {
return (
<Card key={index} card={item} addToDeckDisabled={isCardInDeck(item.translationKey)} addToDeckClick={addToDeck} removeFromDeckClick={removeFromDeck} />
);
})
) : (
<span>
<FormattedMessage id="app.cards.label.no.card.found" defaultMessage="No card found with filter."/>
</span>
)}
</div>
</div>
);
}

Load a component after getting API fetched data in React.js

My components code is like below
componentDidMount = () => {
this.props.dispatch(getCountry());
}
render() {
let rows = this.props.countries.map((item, index) => (//some code here));
return (
<div>
{rows ? (
//components HTML code here
) : (
<img src="loading.gif" alt="Loading ..."/>
)}
</div>
)
}
But the component is loading before API fetched data.
rows is an array hence !rows will still be true. Try this :
return (
<div>
{rows && rows.length ? (
//components HTML code here
) : (
<img src="loading.gif" alt="Loading ..."/>
)}
</div>
)
You can check for rows data since it would be an empty array if not fetched.
return (
<div>
{rows && rows.length ? (
//components HTML code here
) : (
<img src="loading.gif" alt="Loading ..."/>
)}
</div>
)
You can also write your condition like rows && rows.length > 0 same with rows && rows.length. Therows.length if it's empty will resolved to 0 which is false, but if greather than 0 will be true(Typecasting or type conversion).
return (
<div>
{(rows && rows.length > 0 ? (
//components HTML code here
) : (
<img src="loading.gif" alt="Loading ..."/>
)}
</div>
)
Try this componentWillUnmount() {
this.props.countries = []
}, That might help you.

Resources