Conditionally add reference inside loop - reactjs

I am conditionally assigning difference references (ref=) to elements inside a loop depending on index. I know the below is wrong (although works), how should I refactor?
const SortableItem = SortableElement(({ value, index }) => (
<div className="grid-item">
{index == 0 && (
<img className="image-item" src={value.imgUrl} ref={this.bigImage} />
)}
{index == 1 && (
<img className="image-item" src={value.imgUrl} ref={this.secondImage} />
)}
{index > 1 && <img className="image-item" src={value.imgUrl} />}
</div>
));

You can use ternary operator to assign a value based on index. Also make sure to use === when comparing values:
const SortableItem = SortableElement(({ value, index }) => {
const ref = index === 0 ? this.bigImage : index === 1 ? this.secondImage : null;
return (
<div className="grid-item">
<img className="image-item" src={value.imgUrl} ref={ref} />
</div>
);
});

Related

React - Only show item if variable is true

I want to only show each instance of the FeedTag if let soldOut is false. How do I add this condition to each instance of the FeedTag? Each product in the productList has a qty and soldout prop and I only want to show a <FeedTag> where qty !== soldout.
<div>
{productList.length > 0 &&
productList.map((product, i) => {
let soldOut = (productList.qty = productList.soldout);
return (
<FeedTag
data={product}
name={product.headline}
onSelect={(e) => onSelectProduct(e)}
checked={seletedProductList.includes(product._id)}
icon={<img src={helper.CampaignProductImagePath + product.image} alt="" />}
/>
);
})}
</div>
Fix your assignment of soldOut (using ===; I also renamed the variable to available) and use conditional rendering:
...
const available = productList.qty !== productList.soldout;
return (
available && <FeedTag ... />
);
);
Filter out the products that are not sold out first, then map:
<div>
{productList
.filter((product) => product.qty !== product.soldout)
.map((product) => (
<FeedTag
key={product._id}
data={product}
name={product.headline}
onSelect={(e) => onSelectProduct(e)}
checked={seletedProductList.includes(product._id)}
icon={
<img src={helper.CampaignProductImagePath + product.image} alt='' />
}
/>
))}
</div>
Also don't forget the key attribute inside the map.

My console is giving me "Warning: Each child in a list should have a unique "key" prop." despite I gave a unique key

My console keep giving me this error
Warning: Each child in a list should have a unique "key" prop.
despite that I gave a unique key to my map list. My code looks like this:
const [cardItem, setCardItem] = useState(data);
const uniqueIds = [];
const uniqueCat = cardItem.filter((element) => {
const isDuplicate = uniqueIds.includes(element.category);
if (!isDuplicate) {
uniqueIds.push(element.category);
return true;
}
return false;
});
return (
<>
<div className="art-container">
{uniqueCat
.filter((id) => id.id < 73)
.map((item, i) => {
return item.category === "Filmmaking" ||
item.category === "Multimedia" ? (
<div key={i}>
<div className="art-projects-contants">
<h1>{item.category}</h1>
<Card cardItem={cardItem} cat={item.category} />
</div>
</div>
) : (
<>
<div key={i} className="art-img-projects-contants" >
<h1>{item.category}</h1>
<Img cardItem={cardItem} cat={item.category} />
</div>
</>
);
})}
</>
);
I tried to give it a key with the id by {item.id} also giving the second div a key but it still give me the same error. Could the problem be from the uniqueCat because it gave two arrays when I console log it as in the picture?
How can I fix the Unique key problem?
Note: I am using map function in other places in my project but its the only place I have this error.
Your first div has a key, while your second does not:
<div className="art-container">
{uniqueCat
.filter((id) => id.id < 73)
.map((item, i) => {
return item.category === "Filmmaking" ||
item.category === "Multimedia" ? (
<div key={i}>
<div className="art-projects-contants">
<h1>{item.category}</h1>
<Card cardItem={cardItem} cat={item.category} />
</div>
</div>
) : (
<>
<div key={i} className="art-img-projects-contants" > // <== add key here
<h1>{item.category}</h1>
<Img cardItem={cardItem} cat={item.category} />
</div>
</>
);
})}
</div>
The key must be unique on every element in the component tree, your index (i) may have already been used on a different element, avoid using just the loop index as the key.
It's best to use an actual id from the filtered uniqueCat because this id will most likely be unique from any other ids.
Sample code
<div className="art-container">
{uniqueCat
.filter((id) => id.id < 73)
.map((item) => {
return item.category === 'Filmmaking' ||
item.category === 'Multimedia' ? (
<div key={item.id}>...</div>
) : (
<div key={item.id}>...</div>
);
})}
</div>;
If the ids isn't very unique then you can do some form concatenation with template strings using the loop index.
Like this
<div className="art-container">
{uniqueCat
.filter((id) => id.id < 73)
.map((item, i) => {
return item.category === 'Filmmaking' ||
item.category === 'Multimedia' ? (
<div key={`{item.id}-${i}`}>...</div>
) : (
<div key={`{item.id}-${i}`}>...</div>
);
})}
</div>;

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

React: Each child in a list should have a unique "key" prop

Even though I assigned every child a key, I keep getting this error message.
function BertScoreSentence({sentence}: BertScoreSentenceProps) {
let content: JSX.Element[] = []
sentence.words.forEach((word) => {
content.push(
<>
<span key={word.id}>
{word.text}
{bertscores && wordId >= 0 && word.id === bertscores[wordId][3] && isSummaryWord !== visualizeSummary && (
<>(s: {bertscores[wordId][4].toFixed(2)})</>
)}
</span>
</>
)
})
return (
<p id={prefix + "" + sentence.id} className={className}>
{content}
</p>
)
}
I guess something is wrong with using <> or using span?
Any help is appreciated :)
<React.Fragment key={word.id}>
{word.text}
{bertscores && wordId >= 0 && word.id === bertscores[wordId][3] && isSummaryWord !== visualizeSummary && (
<>(s: {bertscores[wordId][4].toFixed(2)})</>
)}
</React.Fragment>
if you're keen about fragments
https://reactjs.org/docs/fragments.html#keyed-fragments
The key must be in the top-most React element returned - if you wrap it inside a fragment, React won't be able to tell.
I'd wrap the in a <span> and push it to content too:
const content = sentence.words.flatMap((word) => [
<span key={word.id}>
{word.text}
{bertscores && wordId >= 0 && word.id === bertscores[wordId][3] && isSummaryWord !== visualizeSummary && (
<>(s: {bertscores[wordId][4].toFixed(2)})</>
)}
</span>,
<span key={word.id + 'space'}> </span>
]);

Render parent element over x items in n array in React?

I have a simple map function:
<div>
{
items.map((item, index)=>(
<p key={index}>{item}</p>
))
}
</div>
Which renders this HTML:
<div>
<p>1</p>
<p>2</p>
<p>3</p>
</div>
How can I insert a span over the first 2 elements so that I have?
<div>
<span>
<p>1</p>
<p>2</p>
</span>
<p>3</p>
</div>
Ive tried:
<div>
{
items.map((item, index)=>(
<>
{ index === 0 && <span> }
<p key={index}>{item}</p>
{ index === items.length - 1 && </span> }
</>
))
}
</div>
But I get an error:
Parsing error: Unexpected token
The error is due to this expressions:
// You must render children if you don't close JSX tag <span></span>
{ index === 0 && <span> }
// Same here, <span/>
{ index === items.length - 1 && </span> }
See JSX in Depth
Also, you trying to group two items under single span, doing it with a single map iteration may be over complicating things.
const items = [1, 2, 3];
const mapToParagraph = (item, index) => <p key={index}>{item}</p>;
const App = () => {
// or slice for more generics
const [first, second, ...rest] = items;
return (
<div>
<span style={{ color: `red` }}>
{[first, second].map(mapToParagraph)}
</span>
{rest.map(mapToParagraph)}
</div>
);
};
Try this, add slash at the end for span.
<div>
{[1, 2, 3, 4, 5, 6].map((item, index) => (
<>
{index === 0 && <span />}
<p key={index}>{item}</p>
{index === [1, 2, 3, 4, 5, 6].length - 1 && <span />}
</>
))}
</div>
EDITED
<div>
{
items.slice(0, 2).length > 0 && (
<span>
{ items.slice(0, 2).map((it, i) => (
<p key={i}>{it}</p>
))}
</span>
)
}
{
items.slice(2).map((it, i) => (
p>{it}</p>
))
}
</div>

Resources