how to dynamically fetch data in react while deploying? - reactjs

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.

Related

When click expand button, scroll fit current expand contents in react

First, I apologize for not explaining well.
When I create multiple Accordion using mui(each AccordionDetails height are 80vh). How can I see the entire content of that selected Accordion?
Thank you.
I attached a screenshot for better understanding and code.
SOLUTION
I solved this one using useref and scrollIntoView.
import React, {useState} from 'react';
import Accordion from '#mui/material/Accordion';
import AccordionSummary from '#mui/material/AccordionSummary';
import AccordionDetails from '#mui/material/AccordionDetails';
import Typography from '#mui/material/Typography';
import ExpandMoreIcon from '#mui/icons-material/ExpandMore';
export default function Example() {
const [data, setData] = useState([
{name:"hello",desc:"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget."},
{name:"hello",desc:"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget."},
{name:"hello",desc:"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget."},
{name:"hello",desc:"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget."},
])
return (
<div>
{data.map((data) => {
return(
<Accordion>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
>
<Typography>{data.name}</Typography>
</AccordionSummary>
<AccordionDetails style={{height:"100vh"}}>
<Typography>
{data.desc}
</Typography>
</AccordionDetails>
</Accordion>
)
})}
</div>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

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";

Problem fetching data in react using getStaticProps

I'm currently trying to fetch some data in my Next.js project using the getStaticProps() function and I continue to get this error:
TypeError: Cannot read property 'map' of undefined
My code looks like this:
export const getStaticProps = async () => {
const data = [
{
"id": 1,
"question": "Lorem ipsum dolor sit amet consectetur adipisicing elit.",
"answer": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Iste magni at magnam placeat. Non, saepe?"
},
{
"id": 2,
"question": "Lorem ipsum dolor sit amet consectetur adipisicing elit.",
"answer": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Iste magni at magnam placeat. Non, saepe?"
}
]
return {
props: {
questions: data
}
}
}
export default function FAQ({ questions }) {
return (
<div className="p-8 grid bg-blanco" >
<div className="grid place-content-center text-center mt-10 md:mt-0" >
<h1 className="text-2xl text-gun-rose-700 font-bold" >¿Tiene preguntas? Mira aquí</h1>
<h3 className="text-gun-rose-300 mt-4 max-w-2xl" >Lorem ipsum dolor sit amet consectetur adipisicing elit. Sunt, suscipit. Aliquid molestias eveniet ullam? Dolores, minus? Perspiciatis neque voluptates iste!</h3>
</div>
{questions.map(q => (
<div className="" key={q.id}>
<h3 className="">{q.question}</h3>
<p className="">{q.answer}</p>
</div>
))}
</div>
)
}
Any guidence will be appreciated, thanks in advance :)
It could be an async issue where questions is not immediately available. Try with a null check at the start of questions.
export default function FAQ({ questions }) {
return (
<div className="p-8 grid bg-blanco" >
<div className="grid place-content-center text-center mt-10 md:mt-0" >
<h1 className="text-2xl text-gun-rose-700 font-bold" >¿Tiene preguntas? Mira aquí</h1>
<h3 className="text-gun-rose-300 mt-4 max-w-2xl" >Lorem ipsum dolor sit amet consectetur adipisicing elit. Sunt, suscipit. Aliquid molestias eveniet ullam? Dolores, minus? Perspiciatis neque voluptates iste!</h3>
</div>
{questions && questions.map(q => (
<div className="" key={q.id}>
<h3 className="">{q.question}</h3>
<p className="">{q.answer}</p>
</div>
))}
</div>
)
}
Edit 1:
The getStaticProps method can only be used on the top level component of a page as stated in the caveats
The fix is to move the getStaticProps method to the top level page component. I've demo'ed this in a sandbox as folder structures are so important, link here.

MUI: ExpansionPanel with TransitionComponent doesn't collapse the item

I'm using ExpansionPanel with TransitionComponent property, when I set default value (Collapse) expansion panel is working fine, but if value is another (Fade, Grow and others), collapsed component has same height as expanded
<ExpansionPanel
expanded={expanded === '1'}
onChange={handleChange('1')}
TransitionComponent={Slide}
TransitionProps={{ mountOnEnter: true }}
className={classnames('accordion-item', expanded === '1' && 'selected')}
>
UPD: there is a snippet https://codesandbox.io/s/vigorous-tree-621cz?fontsize=14&hidenavigation=1&theme=dark
There are two aspects needed to get the Slide transition working appropriately.
In order for the height to adjust appropriately you need to specify both mountOnEnter and unmountOnExit in the TransitionProps.
The other aspect to deal with is the timeout prop. Accordion (previously ExpansionPanel) specifies the timeout as "auto", but "auto" is only supported as a timeout value by Collapse so you need to specify a valid timeout for Slide. In my modified version of your sandbox, I'm using the default values for Slide of 225 for enter and 195 for exit.
Here's a working example:
import React, { useState } from "react";
import {
Accordion,
AccordionSummary,
AccordionDetails,
Slide
} from "#material-ui/core/";
const slideProps = {
mountOnEnter: true,
unmountOnExit: true,
timeout: { enter: 225, exit: 195 }
};
export default function App() {
const [expanded, setExpanded] = useState(null);
return (
<>
<Accordion
TransitionComponent={Slide}
TransitionProps={slideProps}
expanded={expanded === "1"}
onChange={() => setExpanded("1")}
>
<AccordionSummary aria-controls="panel1d-content" id="panel1d-header">
First
</AccordionSummary>
<AccordionDetails>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
malesuada lacus ex, sit amet blandit leo lobortis eget. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada
lacus ex, sit amet blandit leo lobortis eget.
</AccordionDetails>
</Accordion>
<Accordion
TransitionComponent={Slide}
TransitionProps={slideProps}
expanded={expanded === "2"}
onChange={() => setExpanded("2")}
>
<AccordionSummary aria-controls="panel1d-content" id="panel1d-header">
Second
</AccordionSummary>
<AccordionDetails>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
malesuada lacus ex, sit amet blandit leo lobortis eget. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada
lacus ex, sit amet blandit leo lobortis eget.
</AccordionDetails>
</Accordion>
</>
);
}

Resources