I have an API for getting product information. When I want loop in product details, I have a big problem. In the below code, I have three loops. First loop is for getting all the product’s color, second loop is getting available color and last loop is for getting images that have a color. But I get just one pic eventually. When I use condition in gallery loop, my pics repeat as long as my API length.
This is my code:
let arr: any[] = [];
{things.colors.map(
(item: {
ColorCode: any;
Id: string | number | readonly string[] | undefined;
Name: any;
}) =>
things.Counts.map((col: any) => {
if (item.Id == col.ColorId && col.Count > 0) {
return (
<>
{gallery?.map(
(items: { ColorId: any; Link: any }) => {
if (items.ColorId != col.ColorId) {
console.log(arr);
arr= [true,`http://static.etmamode.ir${items.Link}`]
} else {
arr =[false,null];
}
}
)}
<div>
{arr[0] ? (
// console.log(arr[1])
<div className="col-span-1 transition duration-150 ease-in hover:opacity-90">
<img
src={arr[1]}
// alt={`${data?.name}--${index}`}
style={{
borderRadius: "5px",
width: "100px",
height: "100px",
}}
/>
</div>
) : (
<span
style={{
display: "block",
width: "100px",
color: "black",
height: "100px",
borderRadius: "5px",
backgroundColor: `#${item.ColorCode}`,
}}
></span>
)}
>Solution :
Based on the code snippet you’ve provided, it seems like you are trying to display a product’s available colors along with their corresponding images. However, the code you’ve written is causing the images to repeat and display more than once.
One approach you can take is to first filter the gallery array based on the available colors. Then, you can use reduce() to group the filtered images by color. Here’s an example implementation of this approach:
let availableColors = things.Counts
.filter((col: any) => col.Count > 0)
.map((col: any) => col.ColorId);
let filteredGallery = gallery.filter(
(item: any) => availableColors.includes(item.ColorId)
);
let groupedGallery = filteredGallery.reduce((acc: any, item: any) => {
if (!acc[item.ColorId]) {
acc[item.ColorId] = [];
}
acc[item.ColorId].push(item.Link);
return acc;
}, {});
let colorGallery = Object.entries(groupedGallery).map(([colorId, links]) => ({
colorId,
links,
}));
This code first filters the Counts array to get only the available colors, then filters the gallery array to get only the images with those colors. It then uses reduce() to group the filtered images by color ID. Finally, it maps over the resulting object to create an array of objects containing each color’s ID and the corresponding array of image links.
With this data structure in place, you can simplify your rendering logic by using a single loop that maps over the available colors and displays either the color swatch or the image gallery for each one:
{availableColors.map((colorId: any) => {
let links = colorGallery.find((item: any) => item.colorId === colorId)?.links;
if (links) {
return (
<div>
{links.map((link: string) => (
<div className="col-span-1 transition duration-150 ease-in hover:opacity-90">
<img
src={`http://static.etmamode.ir${link}`}
style={{
borderRadius: "5px",
width: "100px",
height: "100px",
}}
/>
</div>
))}
</div>
);
} else {
return (
<span
style={{
display: "block",
width: "100px",
color: "black",
height: "100px",
borderRadius: "5px",
backgroundColor: `#${things.colors.find((item: any) => item.Id === colorId)?.ColorCode}`,
}}
></span>
);
}
})}
This code first finds the array of image links for the current color using find(). If there are links, it maps over them to display the corresponding images. If there are no links, it displays the color swatch instead.
I hope this helps! Let me know if you have any further questions.