React JS: How to add multiple placeholder object inside components - javascript

Sorry this question might be duplicated, but none of the existing answers helped me
I'm a beginner in React and js
I want to add multiple objects inside the component
Like:
src={url}
name={text}
subTitle={subtext}
my index.js
const tableColumns = [
{
title: 'Title/Artist',
dataIndex: 'name',
key: 'name',
render: (text) => (
<div className="d-flex align-items-center">
<AvatarStatus
shape="square"
src="https://i.scdn.co/image/ab67616d00001e02bd26ede1ae69327010d49946"
name={text}
subTitle="Dua Lipa"
/>
</div>
),
},
];
return (
<>
<Table
className="no-border-last"
columns={tableColumns}
dataSource={recentReleasesData}
rowKey='id'
pagination={false}
/>
</>
my data.js
export const RecentReleasesData = [
{
id: '#5332',
artwork: 'https://i.scdn.co/image/ab67616d00001e02bd26ede1ae69327010d49946',
name: 'Future Nostalgia',
artist: 'Dua Lipa',
label: 'Warner Records',
barcode: '19029500',
releasedate: '2021-02-11',
tracks: '11',
promolink: 'Smart Link',
status: 'Approved',
},
{
id: '#6438',
artwork: 'https://i.scdn.co/image/ab67616d00001e02caf82abb2338880577e472be',
name: 'Love',
artist: 'Someonw',
label: 'UMG Records',
barcode: '50029500',
releasedate: '2017-08-21',
tracks: '2',
promolink: 'Smart Link',
status: 'Rejected',
},
];
My comp AvatarStatus.js
import React from 'react';
import PropTypes from 'prop-types'
import { Avatar } from 'antd';
const renderAvatar = props => {
return <Avatar {...props} className={`ant-avatar-${props.type}`}>{props.text}
</Avatar>;
}
export const AvatarStatus = props => {
const { name, suffix, subTitle, id, type, src, icon, size, shape, gap, text,
onNameClick } = props
return (
<div className="avatar-status d-flex align-items-center">
{renderAvatar({icon, src, type, size, shape, gap, text })}
<div className="ml-2">
<div>
{
onNameClick ?
<div
onClick={() => onNameClick({name, subTitle, src, id})}
className="avatar-status-name clickable">{name}
</div>
:
<div className="avatar-status-name"><a href="javascript:void(0)">
{name}</a>
</div>
}
<span>{suffix}</span>
</div>
<div className="text-muted avatar-status-subtitle">{subTitle}</div>
</div>
</div>
)
}
AvatarStatus.propTypes = {
name: PropTypes.string,
src: PropTypes.string,
type: PropTypes.string,
onNameClick: PropTypes.func
}
export default AvatarStatus;
https://reactjs.org/docs/components-and-props.html
components are like JavaScript functions. They accept arbitrary inputs (called “props”) and return React elements describing what should appear on the screen.
This function is a valid React component because it accepts a single “props” (which stands for properties) object argument with data and returns a React element. We call such components “function components” because they are literally JavaScript functions.
codepen example

I found the solution
index.js
render: (_, record) => (
<Flex>
<AvatarStatus
shape="square"
size={50}
src={record.artwork}
name={record.title}
subTitle={record.artist}/>
</Flex>
),

Related

Warning: <Element /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements

I'm trying to automatically create React Elements from strings corresponding to the react-icons library. But I am getting the following errors in the console:
Warning: <RiHeartPulseFill /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.
Warning: The tag <RiHeartPulseFill> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.
Currently I have a data file that consists of a name and iconName (see below)
const categoriesData = [
{
name: 'Vitals',
iconName: 'RiHeartPulseFill',
},
{
name: 'Body',
iconName: 'RiBodyScanFill',
},
{
name: 'Sleep',
iconName: 'RiHotelBedFill',
},
{
name: 'Metabolism',
iconName: 'RiLungsFill',
},
{
name: 'Stress',
iconName: 'RiMentalHealthFill',
},
{
name: 'Strength & Training',
iconName: 'RiRunFill',
},
{
name: 'Lifestyle',
iconName: 'RiCellphoneFill',
},
]
export default categoriesData
I want to dynamically render React elements with the exact name as the iconName in the above datafile as React-icons require specific elements with those names.
Then I try to create a list of navigation links (using the React Router <Link> syntax and adding a React-icon + Name. See the code below:
const menuCategories = categoriesData.map((category) => {
const IconElement = category.iconName
return (
<Link
to={`/data/${category.name.toLowerCase()}`}
key={category.name}
className="flex flex-row items-center gap-2"
>
<IconElement />
{category.name}
</Link>
)
})
The issue I run into is the following error: Warning: <RiHeartPulseFill /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.
I does not seems to be incorrect as it actually IS PascalCase. However when I check dev tools I see the following: <riheartpulsefill></riheartpulsefill>
I have no Idea why this happens. Any solutions?
Extra: Does anyone know how I can also import those icon names based on the initial data files. I'm thinking about creating an icon selection tool, so only the selected icons should be imported from the react-icons lib.
If you want to dynamically render these icon components then you'll typically need to import and specify them in the config instead of strings corresponding to their names.
Example:
import {
RiHeartPulseFill,
RiBodyScanFill,
RiHotelBedFill,
RiLungsFill,
RiMentalHealthFill,
RiRunFill,
RiCellphoneFill,
} from "react-icons/ri";
const categoriesData = [
{
name: 'Vitals',
iconName: RiHeartPulseFill,
},
{
name: 'Body',
iconName: RiBodyScanFill,
},
{
name: 'Sleep',
iconName: RiHotelBedFill,
},
{
name: 'Metabolism',
iconName: RiLungsFill,
},
{
name: 'Stress',
iconName: RiMentalHealthFill,
},
{
name: 'Strength & Training',
iconName: RiRunFill,
},
{
name: 'Lifestyle',
iconName: RiCellphoneFill,
},
];
export default categoriesData;
const menuCategories = categoriesData.map((category) => {
const IconElement = category.iconName;
return (
<Link
to={`/data/${category.name.toLowerCase()}`}
key={category.name}
className="flex flex-row items-center gap-2"
>
<IconElement />
{category.name}
</Link>
);
});
An alternative is to create and export a lookup object for the icon components.
import {
RiHeartPulseFill,
RiBodyScanFill,
RiHotelBedFill,
RiLungsFill,
RiMentalHealthFill,
RiRunFill,
RiCellphoneFill,
} from "react-icons/ri";
export const iconMap = {
RiHeartPulseFill,
RiBodyScanFill,
RiHotelBedFill,
RiLungsFill,
RiMentalHealthFill,
RiRunFill,
RiCellphoneFill,
};
const categoriesData = [
{
name: 'Vitals',
iconName: 'RiHeartPulseFill',
},
{
name: 'Body',
iconName: 'RiBodyScanFill',
},
{
name: 'Sleep',
iconName: 'RiHotelBedFill',
},
{
name: 'Metabolism',
iconName: 'RiLungsFill',
},
{
name: 'Stress',
iconName: 'RiMentalHealthFill',
},
{
name: 'Strength & Training',
iconName: 'RiRunFill',
},
{
name: 'Lifestyle',
iconName: 'RiCellphoneFill',
},
];
export default categoriesData;
const menuCategories = categoriesData.map((category) => {
const IconElement = iconMap[category.iconName];
return (
<Link
to={`/data/${category.name.toLowerCase()}`}
key={category.name}
className="flex flex-row items-center gap-2"
>
<IconElement />
{category.name}
</Link>
);
});
To allow for any react-icons/ri icon then in the UI component import all of react-icons/ri and conditionally render the icon component if it exists.
import { Link } from 'react-router-dom';
import * as ReactRiIcons from "react-icons/ri"; // <-- all RI icons
import * as ReactRxIcons from "react-icons/rx"; // <-- all RX icons
const ReactIcons = { // <-- all merged icons set
...ReactRiIcons,
...ReactRxIcons
};
...
const menuCategories = categoriesData.map((category) => {
const IconElement = ReactIcons[category.iconName];
return (
<Link
to={`/data/${category.name.toLowerCase()}`}
key={category.name}
className="flex flex-row items-center gap-2"
>
{IconElement && <IconElement />} // <-- handle possible undefined icon
{category.name}
</Link>
);
});
...
Use React.createElement. Take a look here to see how: Create react component dynamically
Heres my recursive example:
const demoData = [
{
tagName: 'MyButtonComponent',
children: [
{
tagName: 'MyChildComponent'
}
]
},
{
tagName: 'MyOtherComponent'
},
]
function recursivelyRenderChildren(elements) {
if(elements.length) {
return elements.map((element, index) => {
return React.createElement(elementData.tagName, {
key: element.fieldType+'-'+index,
children: recursivelyRenderChildren(element.children)
});
})
}
}
const arrayOfElements = recursivelyRenderChildren(demoData)

How to .Map over different props that are passed into a component?

I'm new to React but hopefully someone can help!
So I've just created a component that takes in a value (via prop) and then .maps over that value creating an Image slider. The props are all an array of objects that contain different values such as :
const Songs = [
{
artist: 'Artist Name',
song: 'Song Name',
lenght: '2:36',
poster: 'images/....jpg'
},
{
artist: 'Artist Name',
song: 'Song Name',
lenght: '2:36',
poster: 'images/....jpg'
},
]
I have been making the same component over and over again because I don't know how to make the 'prop'.map value dynamic. Essentially I don't know how to change the value before the .map each different prop.
Here's an example. I want to make 'Songs'.map dynamic so the new props can replace that so they can also be mapped. Maybe there's another way. Hopefully some can help.
import React from 'react';
import { FaCaretDown } from 'react-icons/fa';
function ImageSlider({Songs, KidsMovies, Movies, TvShows}) {
return (
<>
{Songs.map((image, index) => (
<div className="movie-card">
<img src={'https://image.tmdb.org/t/p/w500' + image.poster_path}
className='movie-img' />
<h5 className='movie-card-desc'>{image.original_title}</h5>
<p className='movie-card-overview'>{movie.overview}</p>
</div>
))}
</>
);
}
export default ImageSlider;
Given your example,
I feel like all you need is render ImageSlides for each array
function ImageSlider({ items }) {
return (
<>
{items.map((item, idx) => (
<div ... key={idx}> // be careful to not forget to put a key when you map components
...
</div>
))}
</>
);
}
When rendering your component
function OtherComponent({ songs, kidsMovies, movies, tvShows }) {
return (
<div>
<ImageSlider items={songs} />
<ImageSlider items={kidsMovies} />
<ImageSlider items={movies} />
<ImageSlider items={tvShows} />
</div>
);
}

Getting content of currently active Text component wrapped inside popover of antd

I am using antd components for my react app. I have a Text component wrapped inside of Popover component. Now in my case this Popover is applied to one particular column of table, i.e. every row-element in that column has a Popover component rendered for it upon mouse hovering.
title: "Name",
dataIndex: "name",
key: "name-key",
sortType: "string",
sortDirections: ["descend", "ascend"],
sorter: (a, b) => a.name.length - b.name.length,
render: (text, record) => (
<Popover>
<Text onMouseOver={handleOnMouseOverCommitId}> {name} </Text>
</Popover>
)
I want to get hold of the row-element's value, the one contained by the above Text component whenever I hover over it. In this case the value denoted by {name} above.
I tried getting it with e.target.value via onMouseOver event, but it returned undefined.
I think I get the reason behind it, because the event.target returns an html node of type <span>.
With a normal div element e.target.value has worked in the past for me. But doing the same thing with a predefined component like antd's Text seems a bit trickier.
Just to elaborate, the Popover has two buttons and based on which button user clicks, I need to render some other components, something like an overlay component.
But in order to do that I would also need to get hold of the text value which originally triggered the Popover.
Below is the code(most of the things removed for preciseness).
record.name is what I ultimately need to capture.
<Popover
content={
<>
<Space>
<Button onClick={showSomeOverlayPaneForName}>
{"View Details for record.name"}
</Button>
<Button href={"https://abc.xyz.com/" + record.role}>
{"View Role Details"}
</Button>
</Space>
</>
}
trigger={"hover"}
>
<Text style={{"color": blue.primary}} copyable={true} onMouseOver={handleOnMouseOverName}>{record.name}</Text>
</Popover>
The handleOnMouseOverName function(which doesn't work anyway) :
const handleOnMouseOverName = (e) => {
//console.log("e.target.value :--- ", e.target.value);
setCurrentActiveName(e.target.value)
}
And once my currentActiveName variable is set(via useState), I use that value inside my function showSomeOverlayPaneForName
const showSomeOverlayPaneForName = (e) => {
axios
.get(
`some-url`,
{
params: {name: currentActiveName}
}
)
.then((response) => {
setData(response.data);
}).catch(reason => {
//xyz
});
}
You need to pass on the record of the enclosing render function to the handleOnMouseOverName function.
Check the following example
import React from 'react';
import 'antd/dist/antd.css';
import './index.css';
import { Space, Table, Button, Popover } from 'antd';
const App = () => {
const data = [
{
key: '1',
name: 'John Brown',
address: 'New York No. 1 Lake Park',
role: 'admin',
},
{
key: '2',
name: 'Jim Green',
address: 'London No. 1 Lake Park',
role: 'user',
},
{
key: '3',
name: 'Joe Black',
address: 'Sidney No. 1 Lake Park',
role: 'manager',
},
];
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
render: (name, record) => {
const content = (
<>
<Space>
<Button
onClick={() => {
viewDetail(record);
}}
>
{'View Details for ' + record.name}
</Button>
<Button href={'https://abc.xyz.com/' + record.role}>
{'View Role Details'}
</Button>
</Space>
</>
);
return (
<>
<Popover content={content} title="Details">
<div
onMouseOver={() => {
handleOnMouseOverName(record);
}}
>
{name}
</div>
</Popover>
</>
);
},
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
];
const handleOnMouseOverName = (record) => {
console.log(record);
};
const viewDetail = (record) => {
console.log(record);
};
return <Table columns={columns} dataSource={data} />;
};
export default App;
Output:
I hope this helps.
From antd docs: https://ant.design/components/popover/#header
Apparently you're supposed to render the <Popover/> with a content={content}-prop
For example
const content = <div>Content to render under title</div>
const App = () => {
const value = "Text to hover";
return (
<Popover content={content} title="Title">
<Text>{value}</Text>
</Popover>
)
}

React: mapping through a list of svg images

I am trying to map through a list of svg images and show enough description corresponding to the svg image.
index.js
import {ReactComponent as Pic1} from "../../../../assets/buyer-1.svg";
import {ReactComponent as Pic2} from "../../../../assets/buyer-2.svg";
import {ReactComponent as Pic3} from "../../../../assets/buyer-3.svg";
const data = [
{
id: `1`,
title: "Coming soon",
description:'',
img: Pic1,
},
{
id: `2`,
title: "Coming soon",
description:'',
img: Pic2,
},
{
id: `3`,
tile: "Coming soon",
description:'',
img: Pic3,
},
]
function Test() {
return (
{data.map(({ id, title,description, img }) => (
<div key={id} className="guest--item swiper-slide">
<div>
<img key={id} src={img} alt='mySvgImage' />
<h1>{title}</h1>
<h2>{description}</h2>
</div>
</div>
))}
)}
currently when i check my react website i can only see mySvgImage which is the alt 3 times and cant see the actual image
You are importing SVG's as React Component hence you should use them as Component itself.
In you code you are passing a React Component (SVG's which you imported as React Component) as a src attribute to an <img> tag which is invalid.
import React from "react";
import ReactDOM from "react-dom";
import {ReactComponent as Pic1} from "../../../../assets/buyer-1.svg";
import {ReactComponent as Pic2} from "../../../../assets/buyer-2.svg";
import {ReactComponent as Pic3} from "../../../../assets/buyer-3.svg";
const data = [
{
id: `1`,
title: "Coming soon",
description: "",
Image: Pic1
},
{
id: `2`,
title: "Coming soon",
description: "",
Image: Pic2
},
{
id: `3`,
tile: "Coming soon",
description: "",
Image: Pic3
}
];
function Test() {
return (
<>
{data.map(({ id, title, description, Image }) => (
<div key={id}>
<div>
<Image /> {/* Use Image as Component */}
<h1>{title}</h1>
<h2>{description}</h2>
</div>
</div>
))}
</>
);
}
Because you are importing your images the wrong way. I have made this working CodeSandbox which is exactly the same as your example. Check how I imported images and it's working just fine. CodeSandbox
Where you got it wrong is importing SVG as React Component and using for a src attribute in an img tag.
So u don't need to import as ReactComponent.
You can import this way.
import Pic1 from "../../../../assets/buyer-1.svg";
import Pic1 from "../../../../assets/buyer-1.svg";
import Pic2 from "../../../../assets/buyer-2.svg";
import Pic3 from "../../../../assets/buyer-3.svg";
const data = [
{
id: `1`,
title: "Coming soon",
description:'',
img: Pic1,
},
{
id: `2`,
title: "Coming soon",
description:'',
img: Pic2,
},
{
id: `3`,
tile: "Coming soon",
description:'',
img: Pic3,
},
]
function Test() {
return (
{data.map(({ id, title,description, img }) => (
<div key={id} className="guest--item swiper-slide">
<div>
<img key={id} src={img} alt='mySvgImage' />
<h1>{title}</h1>
<h2>{description}</h2>
</div>
</div>
))}
)}

Dynamically load images in create-react-app [duplicate]

I'm trying to display images in a shopping cart i'm making but its not showing up. Do i have to import each image? I know my paths are fine because it worked before.I think there might be something wrong in my product.js file but I can't figure it out.
Here is my Product.js
import React, { Component, PropTypes } from 'react';
class Product extends Component {
handleClick = () => {
const { id, addToCart, removeFromCart, isInCart } = this.props;
if (isInCart) {
removeFromCart(id);
} else {
addToCart(id);
}
}
render() {
const { name, price, currency, image, url, isInCart } = this.props;
return (
<div className="product thumbnail">
<img src={image} alt="product" />
<div className="caption">
<h3>
<a href={url}>{name}</a>
</h3>
<div className="product__price">{price} {currency}</div>
<div className="product__button-wrap">
<button
className={isInCart ? 'btn btn-danger' : 'btn btn-primary'}
onClick={this.handleClick}>
{isInCart ? 'Remove' : 'Add to cart'}
</button>
</div>
</div>
</div>
);
}
}
Product.propTypes = {
id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
price: PropTypes.number,
currency: PropTypes.string,
image: PropTypes.string,
url: PropTypes.string,
isInCart: PropTypes.bool.isRequired,
addToCart: PropTypes.func.isRequired,
removeFromCart: PropTypes.func.isRequired,
}
export default Product;
The data comes from this product.js
const data = [
{
id: 1,
name: 'Reggae Blaster',
price: 10,
currency: 'GOLD',
image: '../assets/blaster_1.png'
},
{
id: 2,
name: 'Juicy Blaster',
price: 10,
currency: 'GOLD',
image: 'images/02.jpg'
},
{
id: 4,
name: 'Full Body Reggae Armor',
price: 20,
currency: 'GOLD',
image: 'images/04.jpg'
},
{
id: 6,
name: 'Reggae Spikes Left',
price: 5,
currency: 'GOLD',
image: 'images/06.jpg'
},
{
id: 5,
name: 'Reggae Spikes Right',
price: 5,
currency: 'GOLD',
image: 'images/05.jpg'
},
{
id: 3,
name: 'Black Full Body Reggae Armor',
price: 20,
currency: 'GOLD',
image: 'images/03.jpg'
}
];
export default data;
I am pulling all the data except the images just don't show up
Assuming that you are using webpack, you need to import the image in order to display it like
<img src={require('images/06.jpg')} alt="product" />
Now that your image data is dynamic,
directly specifying the import path like
<img src={require(image)} alt="product" />
doesn't work.
However you can import the image by making use of template literals like
<img src={require(`${image}`)} alt="product" />
So your code will look like
render() {
const { name, price, currency, image, url, isInCart } = this.props;
return (
<div className="product thumbnail">
<img src={require(`${image}`)} alt="product" />
<div className="caption">
<h3>
<a href={url}>{name}</a>
</h3>
<div className="product__price">{price} {currency}</div>
<div className="product__button-wrap">
<button
className={isInCart ? 'btn btn-danger' : 'btn btn-primary'}
onClick={this.handleClick}>
{isInCart ? 'Remove' : 'Add to cart'}
</button>
</div>
</div>
</div>
);
}
P.S. Also make sure that your image path is relative to the file you are importing them in.
img src={require(${filePath})}
-- working
you also need to add default to get exact URL
img src={require(`${filePath}.default`)}
I adding this comment so that future guys can benefit.
So the problem I faced was I had an array of people, and I needed to display the profile picture of each person
Solution
2 files :
data.js which contains an exported JSON object
main.js which has my react component
Step#1 : data.js
in data.js import all your local image asset files that you need.
ex.
import ProfilePicN from "./ProfilePicN.jpg";
export default [
{
"name": "PersonN",
"image": ProfilePicN
}
]
*important: no quotes around the import, quotes on everything else as they are all literals
Step#2:
import data from "./data.
.
.
.
/*inside the react component*/
{
data.map((dataItem,key)=> {
<img src={dataItem.image}>
})
}
You have to put those images in folder where your bundled application lives.

Categories

Resources