MUI: ExpansionPanel with TransitionComponent doesn't collapse the item - reactjs

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>
</>
);
}

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>

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.

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" }}
/>
...

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.

how to add dynamically multiple posts with jsonplaceholder

help me please, I display the html markup of 6 posts, the first click works correctly, the second click I display the same posts. how should I add six new posts, and so every time I click?
I don't know what can be used instead of the slice method. demo https://jsfiddle.net/u9zc7p5v/13/
const content = mrd.map(function(data, elem) {
return `
<div class="blog__item">
<h2 class="blog__item-title">
${data.title}
</h2>
<input type="checkbox" class="read-more-state" id="post-${elem}" />
<p class="blog__item-text">
${data.body} <span class="blog__item-more">Lorem ipsum dolor sit amet consectetur adipisicing elit. Autem itaque ducimus unde harum vitae quam provident. Lorem ipsum dolor sit amet consectetur adipisicing elit. Dicta sapiente odit laborum tempore sed quaerat a aliquam? Corrupti dolorum, tempora iste qui modi consectetur explicabo quia vel reiciendis nesciunt? Id!</span>
</p>
<label for="post-${elem}" class="blog__item-toggle" >Read More</label>
<div>${elem}</div>
</div>
`
}).slice(startNum, endNum).join('');
Increase the startNum value startNum+=6. then in slice function do startNum + endNum.
$(function(){
const blogs = document.querySelector('.blog__items')
const moreBtn = document.querySelector('.blog-btn')
let startNum = 0;
let endNum = 6;
async function getContent() {
let responce = await fetch('https://jsonplaceholder.typicode.com/posts');
let data = await responce.json();
return data;
}
$(moreBtn).on('click', async function(e) {
let mrd = await getContent();
console.log(mrd.length)
const content = mrd.map(function(data, elem) {
return `
<div class="blog__item">
<h2 class="blog__item-title">
${data.title}
</h2>
<p class="blog__item-text">
${data.body} <span class="blog__item-more">Lorem ipsum dolor sit amet consectetur adipisicing elit. Autem itaque ducimus unde harum vitae quam provident. Lorem ipsum dolor sit amet consectetur adipisicing elit. Dicta sapiente odit laborum tempore sed quaerat a aliquam? Corrupti dolorum, tempora iste qui modi consectetur explicabo quia vel reiciendis nesciunt? Id!</span>
</p>
<label class="blog__item-toggle" >Read More</label>
<div>${elem}</div>
</div>
`
}).slice(startNum, startNum+endNum).join('');
console.log(startNum)
const el = $(content);
$(blogs).append(el)
el.on('click', function() {
});
startNum+= 6
});
});

Resources