Framer Motion animate parent FORM element if form button is clicked - reactjs

I recently started working with Framer Motion. I really like it, and it makes it a lot easier to animate divs and add page transitions. I am having a problem where I am checking if my form is toggled (open/closed) to animate that parent <form> tag using Framer Motion. <motion.form> However, I am already inside the check if the Toggle is active and this way it's firing and checking for two things the animation and toggle state.
How can I simply animate the form if toggleForm is active?
Parent Article.tsx:
import React, { useState, useCallback } from "react";
import { NextPage } from "next";
import Head from "next/head";
import Link from "next/link";
import VideoModule from "#modules/VideoModule";
import HeroModule from "#modules/HeroModule";
import SliderModule from "#modules/SliderModule";
import ImageModule from "#modules/ImageModule";
import QuoteModule from "#modules/QuoteModule";
import PreFooterModule from "#modules/PreFooterModule";
import Footer from "#components/Footer";
import CommentForm from "#components/CommentForm";
const Article: NextPage = () => {
const closeFormText = "Ik reageer later";
const respondFormText = "Ik wil reageren";
const [buttonText, setButtonText] = useState(respondFormText);
const [toggleForm, setToggleForm] = useState(false);
const onToggleForm = useCallback(() => {
setToggleForm(!toggleForm);
!toggleForm ? setButtonText(closeFormText) : setButtonText(respondFormText);
}, [toggleForm, setToggleForm]);
return (
<>
<Head>
<title>Artikel Detail</title>
<meta name="author" content="" />
<meta name="description" content="Developed by Friends For Brands" />
<link rel="icon" href="/favicon.ico" />
</Head>
<HeroModule
title="De headline van deze tekstuele content"
text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
/>
<div className="max-w-screen-xl px-6 pt-16 pb-12 mx-auto border-navyBlue border-b-1 lg:px-8 text-navyBlue ">
<div className="grid w-full grid-cols-12 gap-6">
<aside className=" lg:col-span-3 col-span-full">
<div className="grid grid-cols-12 lg:sticky lg:top-5 lg:block">
<div className="col-span-2 mb-4 avatar">
<div className="w-16 h-16 sm:h-20 sm:w-20 md:w-24 md:h-24 rounded-full ring ring-[#65c3c8] ring-offset-base-100 ring-offset-2">
<img src="https://i.pravatar.cc/300" alt="" />
</div>
</div>
<div className="col-span-8 leading-2">
<p className="font-bold">John Doe</p>
<p>Marketing Manager</p>
<p className="mt-2 md:mt-6">00/00/0000</p>
<p>Leestijd 10 minuten</p>
<div className="mt-6 card-actions">
<Link href="/tag/fashion" passHref>
<span className="text-[11px] font-semibold uppercase cursor-pointer badge badge-outline hover:bg-navyBlue hover:text-white">
Fashion
</span>
</Link>
<Link href="/tag/products" passHref>
<span className="text-[11px] font-semibold uppercase cursor-pointer badge badge-outline hover:bg-navyBlue hover:text-white">
Products
</span>
</Link>
</div>
</div>
</div>
</aside>
<main className="leading-relaxed col-span-full lg:col-span-9 md:text-normal">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.
</p>
<h2 className="mt-3 text-3xl md:text-4xl">Koptekst H2</h2>
<h3 className="mt-3 text-2xl md:text-3xl">Koptekst H3</h3>
<h4 className="mt-3 text-xl md:text-2xl">Koptekst H4</h4>
<ul className="pl-6 my-4 list-disc">
<li>Lorem ipsum dolor sit amet</li>
<li>
Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore
</li>
<li>Et dolore magna aliqua. Ut enim ad minim veniam</li>
<li>
Quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat.
</li>
</ul>
<h2 className="mt-6 text-3xl md:text-4xl">Tussentitel</h2>
<ul className="pl-6 my-4 list-decimal">
<li>Lorem ipsum dolor sit amet</li>
<li>
Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore
</li>
<li>Et dolore magna aliqua. Ut enim ad minim veniam</li>
<li>
Quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat.
</li>
</ul>
<h5 className="font-bold">Tussentitel paragraaf</h5>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.
</p>
<h3 className="mt-6 text-2xl md:text-3xl">Video Module</h3>
<React.StrictMode>
<VideoModule id="mkggXE5e2yk" platform="youtube" />
</React.StrictMode>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.
</p>
<h3 className="mt-6 text-2xl md:text-3xl">Image Module</h3>
<ImageModule
url="https://images.pexels.com/photos/1193743/pexels-photo-1193743.jpeg"
caption="Photo of multicolored abstract painting"
alt="A Pexels image"
/>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.
</p>
<h3 className="mt-6 text-2xl md:text-3xl">Slider Module</h3>
<SliderModule />
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.
</p>
<h3 className="mt-6 text-2xl md:h2text-3xl">Quote Module</h3>
<QuoteModule />
</main>
</div>
</div>
<CommentForm
buttonText={buttonText}
toggleForm={toggleForm}
clickHandle={onToggleForm}
/>
<PreFooterModule />
<Footer />
</>
);
};
export default Article;
Child component CommentForm.tsx:
import { motion } from "framer-motion";
const variants = {
open: { opacity: 1, x: 0 },
closed: { opacity: 0, x: "-100%" },
}
interface CommentFormProps {
buttonText: string;
toggleForm: boolean;
clickHandle: any;
}
const CommentForm = ({
buttonText,
toggleForm,
clickHandle,
}: CommentFormProps) => (
<div className="w-full max-w-4xl px-4 py-20 mx-auto">
<div className="flex gap-4">
<h2 className="text-2xl md:text-4xl">Reacties</h2>
<button
onClick={clickHandle}
className={`inline-flex px-4 py-2 place-items-center text-xs font-medium uppercase transition duration-150 ease-in-out border rounded-full cursor-pointer border-navyBlue hover:bg-navyBlue hover:text-white md:mt-1`}
>
{buttonText}
</button>
</div>
{toggleForm && (
<motion.form className="pt-8" autoComplete="off" animate {toggleForm ? "open" : "closed"}
variants={variants}>
<div className="grid xl:grid-cols-2 xl:gap-6">
<p className="mb-5 font-bold col-span-full md:m-0">Jouw gegevens</p>
<div className="relative z-0 w-full mb-6">
<input
type="text"
name="first_and_lastname"
id="first_and_lastname"
className="block w-full py-3 text-sm bg-transparent border-0 appearance-none text-navyBlue border-b-1 border-navyBlue focus:outline-none focus:ring-0 focus:border-bubblegum peer"
placeholder=" "
required
/>
<label
htmlFor="first_and_lastname"
className="absolute text-md text-navyBlue duration-200 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:left-0 peer-focus:text-navyBlue peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:uppercase peer-focus:scale-75 peer-focus:-translate-y-6"
>
Voor- en Acthernaam
</label>
</div>
<div className="relative z-0 w-full mb-6">
<input
type="email"
name="email"
className="block w-full py-3 text-sm bg-transparent border-0 appearance-none text-navyBlue border-b-1 border-navyBlue focus:outline-none focus:ring-0 focus:border-bubblegum peer"
placeholder=" "
required
/>
<label
htmlFor="email"
className="absolute text-md text-navyBlue duration-200 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:left-0 peer-focus:text-navyBlue peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:uppercase peer-focus:scale-75 peer-focus:-translate-y-6"
>
E-mailadres
</label>
</div>
</div>
<div className="relative z-0 w-full mt-2 mb-6">
<textarea
id="comment"
name="comment"
rows={5}
className="block w-full py-5 text-3xl bg-transparent border-0 appearance-none resize-none text-navyBlue border-b-1 border-navyBlue focus:outline-none focus:ring-0 focus:border-bubblegum peer"
placeholder=" "
required
/>
<label
htmlFor="comment"
className="absolute text-md text-navyBlue duration-200 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:left-0 peer-focus:text-navyBlue peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:uppercase peer-focus:scale-75 peer-focus:-translate-y-6"
>
Reactie
</label>
</div>
<button
type="submit"
className="items-center justify-center px-6 py-1.5 text-sm font-medium uppercase transition duration-150 ease-in-out bg-transparent border rounded-full shadow-sm md:text-lg text-navyBlue border-navyBlue hover:bg-navyBlue hover:text-white"
>
Reageer op artikel
</button>
</motion.form>
)}
</div>
);
export default CommentForm;

You're using the toggleForm state to change the animate property on the form, but you're also using it to conditionally render the form. So as soon as that state switches to false, the form is removed from the DOM, without having a chance to animate to the "closed" variant.
{toggleForm && (
<motion.form className="pt-8" autoComplete="off" animate {toggleForm ? "open" : "closed"}
variants={variants}>
//...etc
)}
The easiest fix would be remove the conditional rendering, and just use the state to change the animation variant on the motion.form element ("open" or "closed").
If you need to actually remove the form from the DOM like that, you can use AnimatePresence with an exit animation (don't forget to give the form a unique key prop!) to have the the element perform an animation before getting removed from the DOM.

Related

Add transition to accordion with react + tailwind

I tried to copy this code and convert native javascript to React, everything but the transition works (the content suddenly grows but it has no animation)
import { useState } from "react"
import { FaMinus, FaPlus } from "react-icons/fa"
function Accordion({ title, content }: { title: string; content: string }) {
const [expanded, setExpanded] = useState(false)
const toggleExpanded = () => setExpanded((current) => !current)
return (
<div className={`transition hover:bg-indigo-50 ${expanded ? "bg-indigo-50" : "bg-white"}`} onClick={toggleExpanded}>
<div className="accordion-header cursor-pointer transition flex space-x-5 px-5 items-center h-16 select-none">
{expanded ? <FaMinus className="text-indigo-500" /> : <FaPlus className="text-indigo-500" />}
<h3>{title}</h3>
</div>
<div className={`px-5 pt-0 overflow-hidden transition ${expanded ? "max-h-fit" : "max-h-0"}`}>
<p className="leading-6 font-light pl-9 pb-4 text-justify">{content}</p>
</div>
</div>
)
}
function AccordionWrapper() {
return (
<div className="h-screen bg-gradient-to-br from-pink-50 to-indigo-100 grid place-items-center">
<div className="w-6/12 mx-auto rounded border">
<div className="bg-white p-10 shadow-sm">
<h3 className="text-lg font-medium text-gray-800">Several Windows stacked on each other</h3>
<p className="text-sm font-light text-gray-600 my-3">The accordion is a graphical control element comprising a vertically stacked list of items such as labels or thumbnails</p>
<div className="h-1 w-full mx-auto border-b my-5"></div>
<Accordion title="What is term?" content="Our asked sex point her she seems. New plenty she horses parish design you. Stuff sight equal of my woody. Him children bringing goodness suitable she entirely put far daughter." />
</div>
</div>
</div>
)
}
You need more styles that just transition, you will need to add overflow-hidden transition-[max-height] duration-500 ease-in to the div that you want to change it's max-height
Also as explained in this question you can't use max-h-fit, you will need to set a value for it max-h-40
const { useState } = React
const minusIcon = '-'
const plusIcon = '+'
function Accordion({ title, content }) {
const [expanded, setExpanded] = useState(false)
const toggleExpanded = () => setExpanded((current) => !current)
return (
<div className="my-2 sm:my-4 md:my-6 shadow-sm cursor-pointer bg-white" onClick={toggleExpanded}>
<div className="px-6 text-left items-center h-20 select-none flex justify-between flex-row">
<h5 className="flex-1">
{title}
</h5>
<div className="flex-none pl-2">{expanded ? minusIcon : plusIcon}</div>
</div>
<div className={`px-6 pt-0 overflow-hidden transition-[max-height] duration-500 ease-in ${expanded ? "max-h-40" : "max-h-0"}`}>
<p className="pb-4 text-left">
{content}
</p>
</div>
</div>
)
}
const lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
ReactDOM.createRoot(
document.getElementById("root")
).render(
<div className='py-16 md:py-20 lg:py-24 px-4 bg-black'>
<section className="max-w-6xl mx-auto text-center">
<Accordion title="Accordion #1" content={lorem} />
<Accordion title="Accordion #2" content={lorem} />
<Accordion title="Accordion #3" content={lorem} />
</section>
</div>
);
<div id="root"></div>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/react#18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#18/umd/react-dom.development.js" crossorigin></script>
When you use transition class only that properties transition when they change:
color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter
You should use transition-all class instead of transition.
tailwind docs

My Toggle/Click event re-renders entire component each time on click?

I have a toggle to show/hide a specific DIV and change the button text based on the current React Hook State. When I view the console log, every single time I click it re-renders the complete page again in Next.js. Not 100% sure if this is normal, But I don't think this should happen if you only toggle one element.
useEffect you can pass property to say whether a specific state is changed or not.
Is there a smarter way of toggling an element and changing its text on click? Without having to re-render the complete code but only the part that you are working with.
import { useEffect, useState } from "react";
import { NextPage } from "next";
import Head from "next/head";
import Link from "next/link";
import HeroModule from "#modules/HeroModule";
import VideoModule from "#modules/VideoModule";
import ImageModule from "#modules/ImageModule";
import SliderModule from "#modules/SliderModule";
import QuoteModule from "#modules/QuoteModule";
import PreFooterModule from "#modules/PreFooterModule";
import Footer from "#components/Footer";
import Comments from "#components/Comments";
const Article: NextPage = () => {
const btnClass = "bg-transparent";
const text = "Reactie plaatsen";
const [buttonActive, setButtonActive] = useState(btnClass);
const [buttonText, setButtonText] = useState(text);
const [openForm, setOpenForm] = useState(false);
const onToggleForm = () => {
setOpenForm(!openForm);
if (!openForm) {
setButtonText("Sluiten");
setButtonActive("bg-navyBlue text-white");
} else {
setButtonActive("bg-transparent text-navyBlue");
setButtonText(text);
}
};
return (
<>
<Head>
<title>Artikel Detail</title>
<meta name="author" content="" />
<meta name="description" content="Developed by Friends For Brands" />
<link rel="icon" href="/favicon.ico" />
</Head>
<HeroModule
title="De headline van deze tekstuele content"
text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
/>
<div className="max-w-screen-xl px-6 pt-16 pb-12 mx-auto border-b-2 border-gray-300 lg:px-8 text-navyBlue ">
<div className="grid w-full grid-cols-12 gap-6">
<aside className=" lg:col-span-3 col-span-full">
<div className="grid grid-cols-12 lg:sticky lg:top-5 lg:block">
<div className="col-span-2 mb-4 avatar">
<div className="w-16 h-16 sm:h-20 sm:w-20 md:w-24 md:h-24 rounded-full ring ring-[#65c3c8] ring-offset-base-100 ring-offset-2">
<img src="https://i.pravatar.cc/300" alt="" />
</div>
</div>
<div className="col-span-8 leading-2">
<p className="font-bold">John Doe</p>
<p>Marketing Manager</p>
<p className="mt-2 md:mt-6">00/00/0000</p>
<p>Leestijd 10 minuten</p>
<div className="mt-6 card-actions">
<Link href="/tag/fashion" passHref>
<span className="text-[11px] font-semibold uppercase cursor-pointer badge badge-outline hover:bg-navyBlue hover:text-white">
Fashion
</span>
</Link>
<Link href="/tag/products" passHref>
<span className="text-[11px] font-semibold uppercase cursor-pointer badge badge-outline hover:bg-navyBlue hover:text-white">
Products
</span>
</Link>
</div>
</div>
</div>
</aside>
<main className="leading-relaxed col-span-full lg:col-span-9 md:text-normal">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.
</p>
<h2 className="mt-3 text-3xl md:text-4xl">Heading 2</h2>
<h3 className="mt-3 text-2xl md:text-3xl">Heading 3</h3>
<h4 className="mt-3 text-xl md:text-2xl">Heading 4</h4>
<ul className="pl-6 my-4 list-disc">
<li>Lorem ipsum dolor sit amet</li>
<li>
Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore
</li>
<li>Et dolore magna aliqua. Ut enim ad minim veniam</li>
<li>
Quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat.
</li>
</ul>
<h2 className="mt-6 text-3xl md:text-4xl">H2: Tussentitel</h2>
<ul className="pl-6 my-4 list-decimal">
<li>Lorem ipsum dolor sit amet</li>
<li>
Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore
</li>
<li>Et dolore magna aliqua. Ut enim ad minim veniam</li>
<li>
Quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat.
</li>
</ul>
<h5 className="font-bold">Tussentitel paragraaf</h5>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.
</p>
<h3 className="mt-6 text-2xl md:text-3xl">H3: Video Module</h3>
<VideoModule id="mkggXE5e2yk" platform="youtube" />
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.
</p>
<h3 className="mt-6 text-2xl md:text-3xl">H3: Image Module</h3>
<ImageModule
url="https://images.pexels.com/photos/1193743/pexels-photo-1193743.jpeg"
caption="Photo of multicolored abstract painting"
alt="A Pexels image"
/>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.
</p>
<h3 className="mt-6 text-2xl md:text-3xl">H3: Slider Module</h3>
<SliderModule />
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.
</p>
<h3 className="mt-6 text-2xl md:h2text-3xl">H3: Quote Module</h3>
<QuoteModule />
</main>
</div>
</div>
<div className="w-full max-w-4xl px-4 py-20 mx-auto">
<div className="flex gap-4">
<h2 className="text-4xl">Comment Module</h2>
<button
onClick={onToggleForm}
className={`items-center justify-center px-4 py-2 text-xs font-medium uppercase transition duration-150 ease-in-out ${buttonActive} border rounded-full shadow-sm cursor-pointer border-navyBlue place-self-start sm:mt-0 hover:border-transparent hover:bg-navyBlue hover:text-white`}
>
{buttonText}
</button>
</div>
{openForm && <p>OPEN</p>}
</div>
{/* <Comments isOpen={openForm} toggleForm={onToggleForm} /> */}
<PreFooterModule />
<Footer />
</>
);
};
export default Article;
You can wrap onToggleForm in useCallback to memoize it. Then that function won't be recreated with every render. Also, be aware that using react strict mode will purposely double render to help you catch any side effects (a good thing and only happens in debug). So you can temporarily remove the <React.StrictMode> tags and see if your console.logs() stop doubling up.

Using React Hooks to filter the posts by date before mapping through the posts - How to?

I am using React Hooks and have a dummy content array of comments which I am mapping through to display it. Now, I am directly mapping through that array, but I would like filter => map before returning the output.
The hook from main file:
const [articleComments, setArticleComments] = useState([
{
name: "John Doe",
publishedAt: "22.03.2022",
image: "https://i.pravatar.cc/300",
post: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
},
{
name: "Jane Doe",
publishedAt: "03.01.2022",
image: "https://i.pravatar.cc/301",
post: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
},
{
name: "Jack Doe",
publishedAt: "17.03.2022",
image: "https://i.pravatar.cc/302",
post: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
},
]);
Comments.tsx:
const Comments = () => (
<div className="w-full px-4 pb-16 pr-4 mx-auto mt-5 md:pt-2 md:max-w-4xl">
<div className="flex flex-col gap-8 leading-relaxed text-md text-navyBlue">
{articleComments.length > 0 &&
articleComments.map(({ image, name, publishedAt, post }: any) => (
<div key={name} className="grid grid-cols-12 gap-4">
<div className="col-span-2 md:col-span-1 avatar">
<div className="w-12 h-12 rounded-full ring ring-[#65c3c8] ring-offset-2">
<img src={image} alt="" />
</div>
</div>
<div className="relative md:-mt-2 col-span-full md:col-span-11">
<h4 className="font-bold">{name}</h4>
<time>{publishedAt}</time>
<p className="mt-2">{post}</p>
</div>
</div>
))}
</div>
</div>
);
export default Comments;

"Your render method should have a return statement" when I do have a return statement

So basically what I am trying to do here is set the toggle state for my modal and then toggle the module on and off via the alert and that should work fine hopefully. However for some reason I am getting the error "Your render method should have a return statement" when I do have a return statement. Does anyone know what could be causing this?
import React, { Component, useState } from "react";
import { Button, Alert, Input, Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";
import ViewEmail from "./viewEmail";
class SingleEmail extends Component {
render() {
const ModalExample = (props) => {
const { buttonLabel, className } = props;
const [modal, setModal] = useState(false);
const toggle = () => setModal(!modal);
return (
<>
<div>
<Modal isOpen={modal} toggle={toggle} className={className}>
<ModalHeader toggle={toggle}>Modal title</ModalHeader>
<ModalBody>
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
sunt in culpa qui officia deserunt mollit anim id est laborum.
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={toggle}>
Do Something
</Button>{" "}
<Button color="secondary" onClick={toggle}>
Cancel
</Button>
</ModalFooter>
</Modal>
<Alert
onClick={toggle}
className="SingleEmail"
style={{
backgroundColor: "white",
border: "1px solid lightgray",
color: "black",
}}
>
<div className="CheckBox">
<Input addon type="checkbox" />
</div>
<div className="MarkImportant">
<i class="fas fa-star"></i>
</div>
<p className="EmailFrom">{this.props.From}</p>
<p className="EmailTitle">{this.props.Subject}</p>
<p className="EmailDate">{this.props.Date}</p>
</Alert>
</div>
</>
);
};
}
}
export default SingleEmail;
You do not have a return statement inside the SingleEmail component but inside the ModalExample component which you have defined inside the render method of SingleEmail.
If you wish to use the ModelExample layout as singleEmail component, you can simply export the same component like
const SingleEmail = (props) => {
const { buttonLabel, className } = props;
const [modal, setModal] = useState(false);
const toggle = () => setModal(!modal);
return (
<>
<div>
<Modal isOpen={modal} toggle={toggle} className={className}>
<ModalHeader toggle={toggle}>Modal title</ModalHeader>
<ModalBody>
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
sunt in culpa qui officia deserunt mollit anim id est laborum.
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={toggle}>
Do Something
</Button>{" "}
<Button color="secondary" onClick={toggle}>
Cancel
</Button>
</ModalFooter>
</Modal>
<Alert
onClick={toggle}
className="SingleEmail"
style={{
backgroundColor: "white",
border: "1px solid lightgray",
color: "black",
}}
>
<div className="CheckBox">
<Input addon type="checkbox" />
</div>
<div className="MarkImportant">
<i class="fas fa-star"></i>
</div>
<p className="EmailFrom">{props.From}</p>
<p className="EmailTitle">{props.Subject}</p>
<p className="EmailDate">{props.Date}</p>
</Alert>
</div>
</>
);
};
export default SingleEmail;
you have no return in render function, you can return ModalExample and things will be fine;
like this:
class SingleEmail extends Component {
render() {
const ModalExample = (props) => {
const { buttonLabel, className } = props;
const [modal, setModal] = useState(false);
const toggle = () => setModal(!modal);
return (
<>
<div>
....
....
....
</div>
</>
);
};
return ModalExample;
}
}

File Upload Not Working In Boostrap Tab

I am developing a web page where the user needs to upload a file. I am using a general technique that sits on top of the \input type="file"\ element that enables me to style it better.
This works fine until I put it in a Bootstrap 4 tab where it appears that the element stops receiving it's Click event.
To demonstrate this I have an HTML page using Jquery and Bootstrap. I have the similar elements sitting inside and outside of the tab. When I click the 'Browse' button on the elements outside the tab it works as expect. However when I click on the 'Browse button inside the tab nothing happens. You need to select "tab 2" then "tab 1" to get the the first tab's content to appear.
There must something in the Bootstrap tab that is blocking this.
Can anybody point me in the right direction as I need to use tabs ?
<!DOCTYPE html>
<title>File Upload</title>
<!-- Latest compiled and minified Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<style>
body {
padding-top: 1em;
}
</style>
<div class="container">
<div class="row">
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link active" id="tab1" data-toggle="tab" role="tab" aria-controls="tab1" aria-selected="true" href="#tab1Content">Tab 1</a>
</li>
<li>
<a class="nav-link" id="tab2" data-toggle="tab" role="tab" aria-controls="tab2" aria-selected="false" href="#tab2Content">Tab 2</a>
</li>
</ul>
<div class="tab-content" id="tabContent">
<div class="tab-pane fade show " id="tab1Content" data-toggle="tab" role="tabpanel" aria-labelledby="tab1">
<div class="row pb-5">
<div class="col-md-12">
<div class="input-group">
<p>Inside of tab</p>
<input type="file" id="fileUploader" name="fileUploader" style="visibility:hidden;" />
<input class="form-control input-xlarge" type="text" id="fileName" value="Choose file">
<div class="input-group-append">
<button id="browseButton" name="browseButton" class="btn btn-success input-group-text">Browse</button>
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="tab2Content" role="tabpanel" aria-labelledby="tab2">
</div>
</div>
</div>
</div>
<div class="container">
<div class="row pb-5">
<div class="col-md-12">
<div class="input-group">
<p>Outside of tab</p>
<input type="file" id="fileUploader2" name="fileUploader2" style="visibility:hidden;" />
<input class="form-control input-xlarge" type="text" id="fileName2" value="Choose file">
<div class="input-group-append">
<button id="browseButton2" name="browseButton2" class="btn btn-success input-group-text">Browse</button>
</div>
</div>
</div>
</div>
</div>
<!-- jQuery library -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<!-- Popper -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<!-- Latest compiled and minified Bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script>
$(document).ready(function () {
$('#browseButton').on('click', function () {
$('#fileUploader').click();
});
$('#fileUploader').change(function () {
$('#fileName').val($(this).val());
});
$('#browseButton2').on('click', function () {
$('#fileUploader2').click();
});
$('#fileUploader2').change(function () {
$('#fileName2').val($(this).val());
});
});
</script>
Please check below code snippet. Might be your HTML tags were not closed properly.
<!DOCTYPE html>
<title>File Upload</title>
<!-- Latest compiled and minified Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<style>
body {
padding-top: 1em;
}
</style>
<div class="container">
<div class="row">
<ul class="nav nav-tabs" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="home-tab" data-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" id="profile-tab" data-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="false">Profile</a>
</li>
<li class="nav-item">
<a class="nav-link" id="contact-tab" data-toggle="tab" href="#contact" role="tab" aria-controls="contact" aria-selected="false">Contact</a>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">
Et et consectetur ipsum labore excepteur est proident excepteur ad velit occaecat qui minim occaecat veniam. Fugiat veniam incididunt anim aliqua enim pariatur veniam sunt est aute sit dolor anim. Velit non irure adipisicing aliqua ullamco irure incididunt irure non esse consectetur nostrud minim non minim occaecat. Amet duis do nisi duis veniam non est eiusmod tempor incididunt tempor dolor ipsum in qui sit. Exercitation mollit sit culpa nisi culpa non adipisicing reprehenderit do dolore. Duis reprehenderit occaecat anim ullamco ad duis occaecat ex.
<p>Inside of tab</p>
<input type="file" id="fileUploader" name="fileUploader" style="visibility:hidden;" />
<input class="form-control input-xlarge" type="text" id="fileName" name="fileName" value="Choose file">
<div class="input-group-append">
<button id="browseButton" name="browseButton" class="btn btn-success input-group-text">Browse</button>
</div>
</div>
<div class="tab-pane fade" id="profile" role="tabpanel" aria-labelledby="profile-tab">
Nulla est ullamco ut irure incididunt nulla Lorem Lorem minim irure officia enim reprehenderit. Magna duis labore cillum sint adipisicing exercitation ipsum. Nostrud ut anim non exercitation velit laboris fugiat cupidatat. Commodo esse dolore fugiat sint velit ullamco magna consequat voluptate minim amet aliquip ipsum aute laboris nisi. Labore labore veniam irure irure ipsum pariatur mollit magna in cupidatat dolore magna irure esse tempor ad mollit. Dolore commodo nulla minim amet ipsum officia consectetur amet ullamco voluptate nisi commodo ea sit eu.
</div>
<div class="tab-pane fade" id="contact" role="tabpanel" aria-labelledby="contact-tab">
Sint sit mollit irure quis est nostrud cillum consequat Lorem esse do quis dolor esse fugiat sunt do. Eu ex commodo veniam Lorem aliquip laborum occaecat qui Lorem esse mollit dolore anim cupidatat. Deserunt officia id Lorem nostrud aute id commodo elit eiusmod enim irure amet eiusmod qui reprehenderit nostrud tempor. Fugiat ipsum excepteur in aliqua non et quis aliquip ad irure in labore cillum elit enim. Consequat aliquip incididunt ipsum et minim laborum laborum laborum et cillum labore. Deserunt adipisicing cillum id nulla minim nostrud labore eiusmod et amet. Laboris consequat consequat commodo non ut non aliquip reprehenderit nulla anim occaecat. Sunt sit ullamco reprehenderit irure ea ullamco Lorem aute nostrud magna.
</div>
</div>
</div>
</div>
<div> </div>
<div> </div>
<div> </div>
<div class="container">
<div class="row pb-5">
<div class="col-md-12">
<div class="input-group">
<p>Outside of tab</p>
<input type="file" id="fileUploader2" name="fileUploader2" style="visibility:hidden;" />
<input class="form-control input-xlarge" type="text" id="fileName2" value="Choose file">
<div class="input-group-append">
<button id="browseButton2" name="browseButton2" class="btn btn-success input-group-text">Browse</button>
</div>
</div>
</div>
</div>
</div>
<!-- jQuery library -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<!-- Popper -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<!-- Latest compiled and minified Bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script>
$(document).ready(function () {
$('#browseButton').on('click', function () {
$('#fileUploader').click();
});
$('#fileUploader').change(function () {
$('#fileName').val($(this).val());
});
$('#browseButton2').on('click', function () {
$('#fileUploader2').click();
});
$('#fileUploader2').change(function () {
$('#fileName2').val($(this).val());
});
});
</script>

Resources