I'm learning React (v18) and I've tried implementing some similar solutions that I've found here, but so far no success. I have been trying display "cards" with names and pictures from a list of authors; the url for the each picture is remote (for example from wikipedia):
export const Authors = () => {
const authors = [
{
id: 1,
name: 'Tayeb Salih',
wikipedia: 'https://en.wikipedia.org/wiki/Tayeb_Salih',
picture_url: 'https://upload.wikimedia.org/wikipedia/commons/a/ae/Tayeb_saleh.jpg'
},
{
id: 2,
name: 'Adolfo Bioy Casares',
wikipedia: 'https://en.wikipedia.org/wiki/Adolfo_Bioy_Casares',
picture_url: 'https://upload.wikimedia.org/wikipedia/commons/a/a9/Bioy.png'
},
{
id: 3,
name: 'Lucy Foley',
wikipedia: 'https://en.wikipedia.org/wiki/Lucy_Foley',
picture_url: 'https://www.intrinseca.com.br/upload/autor/Lucy%20Foley%20G.jpg'
},
{
id: 4,
name: 'Matt Ruff',
wikipedia: 'https://en.wikipedia.org/wiki/Matt_Ruff',
picture_url: 'https://images.gr-assets.com/authors/1597587995p5/40577.jpg'
}];
const cards:any[] = [];
authors.forEach((author, index) => {
const borderColor = index > 1 ? null : index > 0 ? '#57b60a' : '#b60a57';
const item = (
<Card borderColor={borderColor} title={author.name} subtitle={author.id.toString()} key={index}>
<img src={require(`${author.picture_url}`)} alt={author.name} />
</Card>
);
cards.push(item);
});
return (
<section id="section-authors">
<h1>Authors</h1>
<div className="group-cards">
{cards}
</div>
<img
src="https://upload.wikimedia.org/wikipedia/commons/a/a9/Bioy.png"
alt=""
height="200"
/>
</section>
);
};
In this way I get the following error: Uncaught Error: Cannot find module 'https://upload.wikimedia.org/wikipedia/commons/a/ae/Tayeb_saleh.jpg'.
When I change the code to <img src={require(author.picture_url)} alt={author.name} />
, the same error occurs.
If I trying use only <img src={author.picture_url} alt={author.name} />
, error: *Uncaught Error: img is a void element tag and must neither have children
nor use dangerouslySetInnerHTM*... then, with a little bit of insanity: ```<img src={
${author.picture_url}`} alt={author.name} />```... same error...
What's wrong anyway?
EDITED including <Card/>
export const Card = (props: {
title?: string | null | undefined;
subtitle?: string | null | undefined;
borderColor?: string | null | undefined;
children?: any;
}) => {
const cardStyle = {
borderColor: props.borderColor || '#ded3d3',
};
return (
<div className="card-minhoteca" style={cardStyle}>
<CardHeader title={props.title} subtitle={props.subtitle} />
<CardBody>
{
React.Children.map(props.children, (child, i) => {
return React.cloneElement(child, { ...props, key: i });
})
}
</CardBody>
<CardFooter>
<p>Card Footer</p>
</CardFooter>
</div>
);
};
export const CardHeader = (props: { title?: string; subtitle?: string; }) => {
return (
<div className="card-header">
<h3 className="title">{props.title}</h3>
<h4 className="card-subtitle">{props.subtitle}</h4>
</div>
);
};
export const CardBody = (props: {
children?: any
}) => {
return (
<div className="card-body">
{props.children}
</div>
);
};
export const CardFooter = (props: {
children?: any;
callBack?: any;
}) => {
return (
<div className="card-footer">
{props.children}
<button onClick={(e) => {
e.preventDefault();
props.callBack();
}}>Click!</button>
</div>
);
};
UPDATE
You can use
{props.children}
inCard
to render the children in the place needed. This should solve the error if you also changed the way of usingimg
as the original answer.In this use case, the
children
are not modified in their placement, which would not justify the use ofReact.cloneElement()
overprops.children
. Hope this will help.Example:
Original
Instead of using
forEach
you can usemap()
to map outauthors
.This way there is no need to create another
cards
array so component is cleaner.Regarding the
img
, to pass the url it should be<img src={author.pictureUrl} />
, I also changed the property name frompicture_url
topictureUrl
inauthors
.If the issue remains, the error is in
Card
component. Maybe{props.children}
was not placed properly, but will need to see theCard
component to find out.Example: