ReactComponent renders the same SVG Element - reactjs

I am importing an SVG element using the ReactComponent method as below:
import { ReactComponent as Height } from "../../assets/Height.svg";
import { ReactComponent as Closet } from "../../assets/Closet.svg";
import { ReactComponent as Shirt } from "../../assets/Shirt.svg";
When I render them on the screen like this:
<Height />
<Shirt />
<Closet />
It shows the first Icon for all the three renders, for example, for the above code it renders the Height SVG element for all of them.
Here is the full component:
import React from "react";
import styles from "./Features.module.css";
import featureImage from "../../assets/featureImage.png";
import { ReactComponent as Height } from "../../assets/Height.svg";
import { ReactComponent as Closet } from "../../assets/Closet.svg";
import { ReactComponent as Shirt } from "../../assets/Shirt.svg";
import FeatureBackground from "../../assets/FeatureBackground.png";
const Features = () => {
const bodyContent = [
{
icon: <Height />,
title: "Body measurement tracking",
body: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi ",
},
{
icon: <Closet />,
title: "In home trial of clothes and closet",
body: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi ",
},
{
icon: <Shirt />,
title: "Recommendation of clothes using AI",
body: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi ",
},
];
return (
<div className={styles.container}>
<div className={styles.mainSection}>
<div className={styles.images}>
<img
className={styles.featureBackground}
src={FeatureBackground}
alt="feature background"
/>
<img
className={styles.featureImage}
src={featureImage}
alt="features Image"
/>
</div>
<div className={styles.content}>
<h1>EVERYTHING YOU NEED!</h1>
<div className={styles.body}>
{bodyContent.map((content, i) => (
<div key={i} className={styles.bodyContent}>
<div className={styles.icon}> {content.icon} </div>
<div>
<h3>{content.title}</h3>
<p>{content.body}</p>
</div>
</div>
))}
</div>
</div>
</div>
<div className={styles.footerSection}>
<h2>
Enhance your shopping experience with elevated expertise and efficient
time constraints.
</h2>
</div>
</div>
);
};
export default Features;

Related

how to dynamically fetch data in react while deploying?

Here's the thing, it all works fine if I run it with the npm run dev script, but images in testimonials.avatar don't render with npm run build.
const Testimonials = ({ testimonials }) => {
return (
<div id='testimonials' className='mt-20'>
<div className='text-center mb-8'>
<p className='text-xs uppercase mb-4 md:text-base'>Testimonials</p>
<h1 className='text-3xl md:text-5xl font-bold capitalize mb-10'>Read What Other<br />have to Say</h1>
</div>
<div className='flex flex-col gap-4 items-center md:flex-row'>
{testimonials.map(item =>
<div className='bg-light-gray rounded-3xl p-8 transition-transform duration-300 hover:-translate-y-2'>
<div className='w-32 h-32 mx-auto mb-4'>
<img src={item.avatar} alt="Person's avatar" className='rounded-full border' />
</div>
<p className='font-bold text-center'>{item.fullName}</p>
<p className='text-center mt-6'>{item.feedback}</p>
</div>
)}
</div>
</div>
)
}
Here I have a component which receives an array testimonials through props and then renders them in a div.
This is the array in App.jsx file.
const testimonials = [
{
avatar: '../src/images/avatars/avatar-1.png',
fullName: 'Andrew Rathore',
feedback: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ullamcorper scelerisque mi, in malesuada felis malesuada vel. '
},
{
avatar: '../src/images/avatars/avatar-2.png',
fullName: 'Vera Duncan',
feedback: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ullamcorper scelerisque mi, in malesuada felis malesuada vel. '
},
{
avatar: '../src/images/avatars/avatar-3.png',
fullName: 'Mark Smith',
feedback: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ullamcorper scelerisque mi, in malesuada felis malesuada vel. '
}
];
I guess I know that the main reason why it does not work while deploying is because of a non-existent path since I will no longer have src/images/avatar during a deploy.
I also guess this is a dumb question because I am quite new to React and JavaScript in general, but would appreciate any answer regarding the problem.
You have to wrap the avatar path in require() like require('../src/images/avatars/avatar-1.png') I hope this works. thanks
Fixed this by creating an external file and then fetching it to the component like so.
data.js
import avatar1 from '../public/images/avatars/avatar-1.png';
import avatar2 from '../public/images/avatars/avatar-2.png';
import avatar3 from '../public/images/avatars/avatar-3.png';
export const testimonials = [
{
authorImg: avatar1,
authorName: 'Andrew Rathore',
authorText: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ullamcorper scelerisque mi, in malesuada felis malesuada vel.'
},
{
authorImg: avatar2,
authorName: 'Vera Duncan',
authorText: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ullamcorper scelerisque mi, in malesuada felis malesuada vel.'
},
{
authorImg: avatar3,
authorName: 'Mark Smith',
authorText: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ullamcorper scelerisque mi, in malesuada felis malesuada vel.'
}
];
Testimonials.jsx
import React from 'react';
import { testimonials } from '../data/data';
const Testimonials = () => {
return (
<div className='flex flex-col gap-4 justify-between items-center md:flex-row'>
{testimonials.map((testimonial, index) =>
<div key={index} className='bg-light-gray rounded-3xl p-8 transition-transform duration-300 hover:-translate-y-2'>
<div className='w-32 h-32 mx-auto mb-4'>
<img src={testimonial.authorImg} alt="Person's avatar" className='rounded-full border' />
</div>
<p className='font-bold text-center'>{testimonial.authorName}</p>
<p className='text-center mt-6'>{testimonial.authorText}</p>
</div>
)}
</div>
)
}
export default Testimonials;
The main reason why it didn't work well in the first place was the fact that I specified path to the images in the object itself like so:
{
key: '../../../value.png'
}
That is why I ran into as error every time while deploying, 'cause it simply couldn't find that path due to its non-existence.

How to make react-smooth-scrollbar and react-scroll-motion work in the same project?

First I will say how I made the scrollbar work on and then how I tried to run both libraries at the same time and failed to succeed.
At first I created a clean project. I then installed react-smooth-scrollbar and smooth-scrollbar and changed the index.js to the following:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Scrollbar from 'react-smooth-scrollbar';
import SmoothScrollbar from 'smooth-scrollbar';
import OverscrollPlugin from "smooth-scrollbar/plugins/overscroll";
import './index.css';
SmoothScrollbar.use(OverscrollPlugin);
class App extends React.Component {
render() {
return (
<Scrollbar
damping={0.1}
thumbMinSize={20}
syncCallbacks={false}
renderByPixels={true}
alwaysShowTracks={false}
continuousScrolling={true}
wheelEventTarget={null}
plugins={{
overscroll: { effect: "bounce", damping: 0.12 }
}}
>
<section>
<h1>This is a test</h1>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nemo nisi fuga ad. Facilis voluptatum porro accusamus cupiditate aliquam, dignissimos dolorem?</p>
</section>
<section>
<h1>This is a test</h1>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nemo nisi fuga ad. Facilis voluptatum porro accusamus cupiditate aliquam, dignissimos dolorem?</p>
</section>
<section>
<h1>This is a test</h1>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nemo nisi fuga ad. Facilis voluptatum porro accusamus cupiditate aliquam, dignissimos dolorem?</p>
</section>
</Scrollbar>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
And then the following styles in index.css
* {
margin: 0;
padding: 0;
}
section {
height: 100vh;
text-align: center;
font-size: 2rem;
background-color:bisque;
}
section:nth-of-type(2){
background-color: blue;
color: white;
}
Now I had a very simple page with the scrollbar. Next I installed react-scroll-motion and tried to implement it as following:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Scrollbar from 'react-smooth-scrollbar';
import SmoothScrollbar from 'smooth-scrollbar';
import OverscrollPlugin from "smooth-scrollbar/plugins/overscroll";
import './index.css';
import { Animator, ScrollContainer, ScrollPage, batch, Fade, FadeIn, FadeOut, Move, MoveIn, MoveOut, Sticky, StickyIn, StickyOut, Zoom, ZoomIn, ZoomOut } from "react-scroll-motion";
SmoothScrollbar.use(OverscrollPlugin);
class App extends React.Component {
render() {
return (
<ScrollContainer>
<ScrollPage>
<Scrollbar
damping={0.1}
thumbMinSize={20}
syncCallbacks={false}
renderByPixels={true}
alwaysShowTracks={false}
continuousScrolling={true}
wheelEventTarget={null}
plugins={{
overscroll: { effect: "bounce", damping: 0.12 }
}}>
<section>
<h1>This is a test</h1>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nemo nisi fuga ad. Facilis voluptatum porro accusamus cupiditate aliquam, dignissimos dolorem?</p>
</section>
<section>
<Animator animation={batch(Fade(), MoveOut(0, -200))}>
<h1>This is a test</h1>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nemo nisi fuga ad. Facilis voluptatum porro accusamus cupiditate aliquam, dignissimos dolorem?</p>
</Animator>
</section>
<section>
<h1>This is a test</h1>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nemo nisi fuga ad. Facilis voluptatum porro accusamus cupiditate aliquam, dignissimos dolorem?</p>
</section>
</Scrollbar>
</ScrollPage>
</ScrollContainer>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
And the code above proceeds to not do the requested animation, I tried running react-scroll-motion on it's own as well and that worked fine. So, how do I make react-smooth-scrollbar and react-scroll-motion work in the same project?

React object rendering to fontawesome

how do i render an object to a font awesome component. i have an object with different properties and i am rendering them dynamically into my cards component so i have many cards with different contents. below is my code.
import React from "react";
import "../Styles/card.css";
import "bootstrap/dist/css/bootstrap.css";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faCar, faTruck, faHome } from "#fortawesome/free-solid-svg-icons";
const Card = () => {
const Cards = [
{
_uid: "BUY6Drn9e1",
Icon: "faHome",
head: "Free and Fast",
text: "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Aliquam
tempora illum magni minima dolor id sequi quibusdam omnis.",
},
{
_uid: "BUY6Drn9e1",
Icon: "faTruck",
head: "Post Transportation",
text: "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Aliquam tempora illum magni minima dolor id sequi quibusdam omnis.",
},
{
_uid: "BUY6Drn9e1",
Icon: "faCar",
head: "Free and Fast",
text: "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Aliquam tempora illum magni minima dolor id sequi quibusdam omnis.",
},
];
const renderCard = (Card, index) => {
const shape = Card.Icon;
console.log(shape);
return (
<div className="card carded col mx-1 mb-2" key={index}>
<div className="flex">
<div className=" sameRow icon">
{/* <i class="bi bi-truck" style={{ fontSize: 35 }}></i> */}
</div>
<div className="sameRow body">
<FontAwesomeIcon
icon={faCar}
className="pic"
style={{ fontSize: 25, color: "#66b2e9" }}
/>
<h3 className="head">{Card.head}</h3>
<p className="text">{Card.text}</p>
</div>
</div>
</div>
);
};
return <div className="row mt-5 pt-5 px-5">{Cards.map(renderCard)}</div>;
};
export default Card;
i am trying to replace the faCar with {Card.Icon}
You have made a mistake,
Link the font awesome icon to each item using the import name, not as strings.
const Cards = [
{
_uid: "BUY6Drn9e1",
Icon: faHome,
head: "Free and Fast",
text:
"Lorem ipsum dolor sit, amet consectetur adipisicing elit. Aliquam tempora illum magni minima dolor id sequi quibusdam omnis."
},
{
_uid: "BUY6Drn9e1",
Icon: faTruck,
head: "Post Transportation",
text:
"Lorem ipsum dolor sit, amet consectetur adipisicing elit. Aliquam tempora illum magni minima dolor id sequi quibusdam omnis."
},
{
_uid: "BUY6Drn9e1",
Icon: faCar,
head: "Free and Fast",
text:
"Lorem ipsum dolor sit, amet consectetur adipisicing elit. Aliquam tempora illum magni minima dolor id sequi quibusdam omnis."
}
];
Access it when iterating as you have done for the text
...
<FontAwesomeIcon
icon={Card.Icon}
className="pic"
style={{ fontSize: 25, color: "#66b2e9" }}
/>
...

Props not rendering for storybook component

I have a component that will take an array of objects and will render a grid of lists
//Awards
import React from "react";
import MarkDown from "components/Design/MarkDown";
import { Grid } from "components/Design/Grid/Grid";
export const Awards = ({ list }) => {
return (
<Grid>
{list
.sort((a, b) => b.year - a.year)
.map((award) => (
<div
key={award.id}
className="flex flex-col gap-16 font-mulish col-span-4">
<h3 className="font-bold text-14-24 text-gray-dark">
{award.year}
</h3>
<div className="text-14-24 text-gray-text">
<MarkDown>{award.description}</MarkDown>
</div>
</div>
))}
</Grid>
);
};
When I try to write a story for the component, I get a warning TypeError: Object(...) is not a function. After several refresh I get Cannot access 'Awards' before initialization
//Awards.stories.jsx
import React from "react";
import { Awards } from "components/Awards";
export default {
title: "component/Awards",
component: Awards,
};
const list = [
{
id: 1,
year: 2018,
description:
"- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n\n - Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n\n - Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n\n - Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
},
{
id: 2,
year: 2017,
description:
"- Lorem ipsum dolor sit amet\n\n - consectetur adipiscing elit.",
},
{
id: 3,
year: 2016,
description:
"- Lorem ipsum dolor sit amet\n\n - consectetur adipiscing elit.",
},
{
id: 4,
year: 2015,
description:
"- Lorem ipsum dolor sit amet\n\n - consectetur adipiscing elit.",
},
{
id: 5,
year: 2014,
description: "- Lorem ipsum dolor sit amet",
},
];
export const AwardsBlock = () => {
return <Awards list={list} />;
};
While debugging I found that if replace the part
{list
.sort((a, b) => b.year - a.year)
.map((award) => (
<div
key={award.id}
className="flex flex-col gap-16 font-mulish col-span-4">
<h3 className="font-bold text-14-24 text-gray-dark">
{award.year}
</h3>
<div className="text-14-24 text-gray-text">
<MarkDown>{award.description}</MarkDown>
</div>
</div>
))}
with something static
<span>——</span>
It works like a charm. Maybe something to do with lists throwing some error or not rendering.
What am I missing here?
Did you mean to do a named import for the Markdown component?
As in
import {MarkDown} from "components/Design/MarkDown";
instead of
import MarkDown from "components/Design/MarkDown";

MUI: how to show tooltip component over selected text?

Like on medium:
Tooltip from matetial-ui react framework.
some ideas:
wrap selected text with <span> and use that element as reference node
of tooltip (over complicated I guess)
create tooltip w/o child and specify
absolute position based on selected text
any other ideas?
The simplest: https://www.w3schools.com/css/css_tooltip.asp
The more effective: https://chrisbracco.com/a-simple-css-tooltip/
:)
Medium.com uses popper.js. I found this out by searching the tag parameters in Medium's HTML.
<div class="bz fx mc yw"
style=
"position: absolute; inset: auto auto 0px 0px; transform: translate(692px, 1233px);"
data-popper-reference-hidden="false"
data-popper-escaped="false"
data-popper-placement="top">
https://popper.js.org/
It does the thing where it repositons the popup if you scroll, I checked.
I used the popper component instead of tooltip component link: https://mui.com/material-ui/react-popper/#virtual-element
demo: https://codesandbox.io/s/iztu66?file=/demo.js
code
import * as React from 'react';
import Popper from '#mui/material/Popper';
import Typography from '#mui/material/Typography';
import Fade from '#mui/material/Fade';
import Paper from '#mui/material/Paper';
export default function VirtualElementPopper() {
const [open, setOpen] = React.useState(false);
const [anchorEl, setAnchorEl] = React.useState(null);
const handleClose = () => {
setOpen(false);
};
const handleMouseUp = () => {
const selection = window.getSelection();
// Resets when the selection has a length of 0
if (!selection || selection.anchorOffset === selection.focusOffset) {
handleClose();
return;
}
const getBoundingClientRect = () =>
selection.getRangeAt(0).getBoundingClientRect();
setOpen(true);
setAnchorEl({
getBoundingClientRect,
});
};
const id = open ? 'virtual-element-popper' : undefined;
return (
<div onMouseLeave={handleClose}>
<Typography aria-describedby={id} onMouseUp={handleMouseUp}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ipsum purus,
bibendum sit amet vulputate eget, porta semper ligula. Donec bibendum
vulputate erat, ac fringilla mi finibus nec. Donec ac dolor sed dolor
porttitor blandit vel vel purus. Fusce vel malesuada ligula. Nam quis
vehicula ante, eu finibus est. Proin ullamcorper fermentum orci, quis finibus
massa. Nunc lobortis, massa ut rutrum ultrices, metus metus finibus ex, sit
amet facilisis neque enim sed neque. Quisque accumsan metus vel maximus
consequat. Suspendisse lacinia tellus a libero volutpat maximus.
</Typography>
<Popper
id={id}
open={open}
anchorEl={anchorEl}
transition
placement="bottom-start"
>
{({ TransitionProps }) => (
<Fade {...TransitionProps} timeout={350}>
<Paper>
<Typography sx={{ p: 2 }}>The content of the Popper.</Typography>
</Paper>
</Fade>
)}
</Popper>
</div>
);
}
You can add your own buttons after fade component or inside in paper component.

Resources