REACT onMouseEnter/onMouseLeave PopUp flickering loop - javascript

I'm building a button that shows a PopUp when hovered. To achieve this, I'm using the state "activeToolTip" that turns true "onMouseEnter" / false "onMouseLeave", and in turn renders the PopUp ({activeToolTip ? ( <>popUp<> : null)).
However, when hovering the button, the PopUp flickers between the onMouseEnter and onMouseLeave.
Can you help me understand the problem?
My code:
import { TooltipClose } from "../../../utils/svg";
export default function CustomTooltipsRed() {
const [activeToolTip, setActiveToolTip] = useState(false);
let TooltipTimeout;
const showToolTip = () => {
TooltipTimeout = setTimeout(() => {
setActiveToolTip(true);
}, 50);
};
const hideToolTip = () => {
setActiveToolTip(false);
clearInterval(TooltipTimeout);
};
return (
<div className="flex items-center justify-center ">
<button
className="bg-pink-500 text-white font-bold uppercase text-sm px-6 py-3 rounded shadow mr-1 mb-1 "
onMouseEnter={() => showToolTip()}
onMouseLeave={() => hideToolTip()}
>
Hover button
</button>
{activeToolTip ? (
<>
<div className="justify-center items-center flex fixed inset-0 outline-none focus:outline-none ">
<div className="relative w-auto my-6 mx-auto max-w-xl">
{/*content*/}
<div className="border-0 rounded-lg shadow-lg relative flex flex-col w-full bg-[#F43F5E] outline-none">
{/*header*/}
<div className="flex items-center justify-start p-2 rounded-t">
<div className="mr-2">
<i><TooltipClose /></i>
</div>
<h3 className="text-base font-semibold text-white">
P1 - Priority Issue
</h3>
</div>
{/*body*/}
<div className="relative p-6 flex-auto bg-[#1E293B] rounded-b-lg">
<p className="text-[#E2E8F0] leading-relaxed">
We have detected that your tenant has legacy protocols enabled.
Why is this an issue? Legacy protocols can not enforce multi factor
authentication and are considered a security risk.
</p>
Read More
</div>
</div>
</div>
</div>
<div className="inset-0 z-40"></div>
</>
) : null}
</div >
);
}

Add pointer-events-none to the tooltip.

Related

TailwindCSS styling applies to one React Component list but not the other

Hello I have two cards but one of them is not applying it's TailwindCSS stuff to the divs at all. I hope it's just some stupid error because I'm kind of scratching my head.
Is the relevant incorrect code:
Where it's being rendered in the index page:
Dashboard.tsx:
<div className="flex flex-col border border-red-700">
{orders.map(
({ id, managerId, invoiceNumber, companyName, contact, partNumbers, partNames, quote, locationOnServer, reportType, createdAt }) => {
return (
<WorkOrderCard id={id} managerId={managerId} invoiceNumber={invoiceNumber} companyName={companyName} contact={contact} partNumbers={partNumbers} partNames={partNames} quote={quote} locationOnServer={locationOnServer} reportType={reportType} createdAt={createdAt} timesheet={[]} />
)
}
)}
And here is the component definition WorkOrderCard.tsx:
export default function WorkOrderCard(props) {
const { id, managerId, invoiceNumber, companyName, contact, partNumbers, partNames, quote, locationOnServer, reportType, createdAt, timesheet} = props;
const [manager, setManager] = React.useState<string>("");
useEffect(() => {
if (manager !== undefined) {
const res = fetch("/api/users/get/" + managerId, {
method: 'GET',
}).then((res) => {
if (res.ok) {
res.json().then((manager) => {
setManager(manager.name);
})
} else {
console.log("There was an error fetching the ticket");
// setErrorMessage(res.statusText)
}
})
}
}, [])
return (
/* Trying to draw an outline around the div but It doesn't appear */
<div className="flex outline outline-red-600">
<div className='flex flex-col'>
<div className="flex flex-row">
<div className="flex">Invoice #{invoiceNumber}</div>
<div className="flex">{companyName}</div>
</div>
<div className="card-body">
<div className="card-text">
<strong>Contact:</strong> {contact || 'N/A'}
</div>
<div className="card-text">
<strong>Part Numbers:</strong>{' '}
{partNumbers.length > 0 ? partNumbers.join(', ') : 'N/A'}
</div>
<div className="card-text">
<strong>Part Names:</strong>{' '}
{partNames.length > 0 ? partNames.join(', ') : 'N/A'}
</div>
<div className="card-text">
<strong>Quote:</strong> ${quote}
</div>
<div className="card-text">
<strong>Location on Server:</strong> {locationOnServer}
</div>
<div className="card-text">
<strong>Report Type:</strong> {reportType}
</div>
<div className="card-text">
<strong>Created At:</strong> {createdAt.toString()}
</div>
<div className="card-text">
</div>
<div className="card-text">
<strong>Manager:</strong> {manager}
</div>
{timesheet.length > 0 && (
<div className="card-text">
<strong>Time Sheet:</strong>
<ul>
{timesheet.map((time) => (
<li key={time.id}>
{new Date(time.date).toLocaleString()} - {new Date(time.date).setHours(new Date(time.date).getHours() + time.hours).toLocaleString()}
</li>
))}
</ul>
</div>
)}
</div>
</div>
</div>
);
};
The working code is called like this Dashboard.tsx:
<div className="flex flex-col justify-evenly border border-red-700">
{tickets.map(
({ id, creator, broken_item, issue_desc, loc, prio, active, creatorName, createdAt }) => {
return (
<TicketGUI className="m-3" id={id} creator={creator} broken_item={broken_item} issue_desc={issue_desc} loc={loc} prio={prio} active={active} name={creatorName} createdAt={createdAt} />
)
}
)}
<div className="flex justify-between m-2">
<button onClick={() => {
ticketPageSelect(currentSession.user.id, tickets[0].id, setTickets, true, pageSize)
}} className="justify-end px-4 py-2 text-sm text-blue-100 bg-blue-500 rounded shadow">
Prev
</button>
<button onClick={() => {
ticketPageSelect(currentSession.user.id, tickets[tickets.length - 1].id, setTickets, false, pageSize)
}} className="justify-end px-4 py-2 text-sm text-blue-100 bg-blue-500 rounded shadow">
Next
</button>
</div>
</div>
And here is the working component TicketGUI.tsx:
export default function TicketGUI(props){
const handlePress = async (e) => {
Router.push('/tickets/'+props.id)
}
return (
<div className="flex flex-col rounded-lg shadow-lg p-2 m-3 outline outline-blue-300">
<div className="flex ">
<img
className="object-cover h-12"
src={props.active ? "/inprocess.png" : "/fixed.png"}
alt="image"
/>
<h1 className=" ml-2 text-xl font-semibold tracking-tight text-blue-600 whitespace-nowrap">
{props.broken_item} - TicketID: {props.id}
</h1>
</div>
<div className="p-4">
<p className="mb-2 leading-normal">
{props.issue_desc}
</p>
<div className="flex w-full">
<button onClick={handlePress} className="px-4 py-2 text-sm text-blue-100 bg-blue-500 rounded shadow">
View Details
</button>
<p className="p-2">
{format(new Date(props.createdAt),'MM/dd/yyyy')}
</p>
</div>
</div>
</div>
);
}
Any help would be appreciated Chat-GPT suggested this but no dice and I factored out className from props:
It looks like the problem is that the className prop is being passed
to the component but it is not being used to apply classes to the
elements within the component. In the code you posted, the className
prop is only being used to specify the component's own class, but it
is not being used to apply classes to the elements within the
component.
To fix this, you can either use the className prop to specify the
classes for each element within the component, or you can use the
className prop to specify the classes for the component itself and
then use the class prop to specify the classes for the elements within
the component.
For example, you could change this line:
<div className={className}>
to this:
<div className={className}>
<div className='flex flex-col'>
<div className="flex flex-row">
...
</div>
<div className="card-body">
...
</div>
</div>
</div>

Not able to locate Hydration Error: Initial UI does not match what was rendered

I have been looking at this piece of code for over 2 days now, and i have not been able to locate my Hydration error. It is driving me crazy. Could some one maybe take a look at it for me? Are there any tips and tricks to spot these kind of errors more quickly, would love to know!
I'am using nextjs and using axios for the get resquest
These are the errors:
Error: Hydration failed because the initial UI does not match what was rendered on the server.
Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
react-dom.development.js?ac89:19849 Uncaught Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
export async function getStaticProps() {
try {
const res = await axios.get('https://open.data.amsterdam.nl/Festivals.json')
const events = res.data;
return {
props: {
events: events.slice(0, 10)
}
}
} catch (error) {
console.log(error)
}
}
function EventsCards({events}) {
return (
<div>
<a id="pressable-card max-w-md">
<div id="featured-event-container" className="bg-black rounded-md bg-opacity-20 bg-blur-sm max-w-xs shadow-lg">
<div id="event-banner">
<img className="max-w-lg w-full h-full" src={events.media[0].url }/>
</div>
<div className="text-white pl-2">
<h1 className="text-lg font-medium text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-pink-600">{events.title}</h1>
<a className="text-sm uppercase">{events.title}</a>
<a className="text-xs text-">Friday 20 Jan | 13:00 - 02:00</a>
</div>
<div className="py-2 px-2">
<p className="text-slate-200 font-normal border-[1px] py-[2px] px-[4px] rounded-lg border-slate-400 w-8 text-[8px]">Techno</p>
</div>
</div>
</a>
</div>
)
}
function Events({events}) {
return (
<div className="bg-gradient-to-t from-gray-500 to-gray-900 h-full bg-blur-sm pt-2">
<div className="max-w-6xl mx-auto">
<div className="px-8 ">
<div className="flex">
<h1 className="text-white font-regular opacity-100 tracking-wider sm:text-xl md:text-2xl">Featured events in Amsterdam</h1>
<div className="pl-2 my-auto">
<img className="rounded-full w-8 h-8 md:w-6 md:h-6 border-gray-400" src="https://www.fotw.info/images/n/nl.gif"></img>
</div>
</div>
<ul className="grid grid-cols-1 md:grid-cols-2 pt-4 md:w-full">
<div id="featured-wrapper" className="bg-black rounded-md bg-opacity-20 bg-blur-sm max-w-xs shadow-lg">
<a id="pressable-card max-w-md">
<div id="featured-event-container">
<div id="event-banner">
<img className="max-w-lg max-h-lg w-full h-full" src='https://d1as2iufift1z3.cloudfront.net/rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBaWpqIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--696c8f363a91d0501e8ae333fc9d42e5fd9c225f/ERT_HOLLAND_SIGNUP_banner%20(1).jpg?proxy=true'></img>
</div>
<div className="text-white pl-2">
<h1 className="text-lg font-medium text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-pink-600">El Row Town 2022 - Holland</h1>
<a className="text-sm uppercase">{events.title}</a>
<a className="text-xs text-">Friday 1 Jan | 11:00 - 04:00</a>
</div>
<div className="py-2 px-2">
<a className="text-slate-200 font-normal border-[1px] py-[2px] px-[4px] rounded-lg border-slate-400 w-8 text-[8px]">Techno</a>
</div>
</div>
</a>
</div>
<div className="text-red-400"><h1>test</h1></div>
</ul>
</div>
{/* Amsterdam Events */}
<div className="flex justify-center py-8">
<button className="text-[8px] uppercase font-medium rounded-md py-[8px] px-2 bg-white">see events in Amsterdam</button>
</div>
{/* All Events */}
<div className="mx-auto max-w-6xl w-full">
<h1 className="px-8 text-white font-regular tracking-wider text-xl md:text-2xl">Amsterdam</h1>
</div>
<div className="max-auto max-w-6xl">
<div className="grid grid-cols-1 md:grid-cols-3 pt-4 md:w-full w-full px-8 gap-4">
{events.map((event) => (
<EventsCards key={event.id} events={event} />
))}
</div>
</div>
</div>
</div>
)
}
export default Events;```
There are a couple of issues with your code that are causing issues:
Invalid markup (anchor tags inside other anchor tags, ul tags without li children).
You are passing the prop events to your <EventCard /> component (it should have a name that is different from the events array retrieved server-side)
You are using a event.id for your key prop when none exists (it should be event.trcid).
Here's a basic working version of your components:
export default function Events({ events }) {
return (
<>
{events.map((event) => (
<EventsCards key={event.trcid} event={event} />
))}
</>
);
}
function EventsCards({ event }) {
return <div>{event.title}</div>;
}
export async function getStaticProps() {
try {
const res = await axios.get(
'https://open.data.amsterdam.nl/Festivals.json'
);
const events = res.data;
return {
props: {
events,
},
};
} catch (error) {
console.log(error);
}
}
More often, it's best to start by getting the data on the page and then add in your additional content and styles.
It happens because you make some changes on the server side and save them before the Fast-Refresh completes hence causing a hydration error. You can manually reload the page after completing saving the changes or wait for Fast-Refresh to complete and then save your codes.

How to transition div using Tailwindcss in React

I have a Menu panel next to my sider. I am trying to add a drawer type animation however I can't seem position open/close within the pink column
const album = ["Album1", "Album2", "Album3"];
export const Menu = () => {
const [open, setOpen] = useState(false);
return (
<div className="flex flex-1 flex-col p-3">
<h2 className="text-lg font-medium text-gray-900">Album</h2>
<div className="flex-1">
<div className="flex flex-1 flex-col space-y-3 py-3">
{album.map((name) => (
<button
key={name}
id={name}
className={`flex space-x-2 items-center`}
onClick={() => setOpen(true)}
>
<span>{name}</span>
</button>
))}
</div>
</div>
<aside
onClick={() => setOpen(false)} //temporary
className={`transform top-0 left-0 w-72 bg-blue-400 fixed h-full overflow-auto ease-in-out transition-all duration-1000 z-30 ${
open ? "translate-x-14" : "-translate-x-full"
}`}
>
hello
</aside>
</div>
);
};
Javascript. Just add a eventListener to the 'button' which will handle the actions. In the eventListener, remove or add a css class. For example, by default the position is '-100px right' with css set position to '300px right', also add a transition 'all 300ms ease'. Now you element start with no css, and when user press button add the class.
<div class="text-3xl font-bold underline transition-all duration-300" id="must-change">
Lorem Ipsu
</div>
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold p-3 rounded" id="press-me">
Button
</button>
<script>
const btn = document.querySelector("#press-me")
const mustChange = document.querySelector("#must-change")
btn.addEventListener("click", () => {
mustChange.classList.toggle("font-bold")
})
</script>
I set 'transition all' but you can use a specific transition if you want.

How to map large data in nextjs when in viewport?

I want to make make a dropdown where a user can select an erc20 token from a tokenlist in Nextjs.
I tried a regular mapping function on the token list but then the site doesn't respond and is very slow because the tokenlist.json. I would like to render the data when in viewport. How can I achieve this?
I would like to make it fast, like in the token select modal in
Uniswap
I used nextjs Image and this loads the token image when in view but it is still slow because it needs to render the token name and symbol
This is how I fetch the tokenlist and render it:
import { Fragment, useEffect, useState } from 'react';
import { Combobox, Transition } from '#headlessui/react';
import { CheckIcon, SelectorIcon } from '#heroicons/react/solid';
import { PlusSmIcon } from '#heroicons/react/outline';
import axios from 'axios';
import tokensJson from '../web3/tokens.json';
import Image from 'next/image';
export default function SelectErc20() {
const [selected, setSelected] = useState(tokensJson.tokens[0]);
const [tokenlist, setTokenlist] = useState([]);
const [query, setQuery] = useState('');
const filteredTokens =
query === ''
? tokenlist
: tokenlist.filter((token) =>
token.name
.toLowerCase()
.replace(/\s+/g, '')
.includes(query.toLowerCase().replace(/\s+/g, ''))
);
useEffect(() => {
axios
.get('https://tokens.coingecko.com/uniswap/all.json')
.then((res) => {
setTokenlist(res.data.tokens);
})
.catch(setTokenlist(tokensJson.tokens));
}, []);
return (
<div className="flex items-center space-x-3">
<img src={selected.logoURI} alt="token" className="h-6 w-6" />
<div className="w-64">
<Combobox value={selected} onChange={setSelected}>
<div className="relative mt-1">
<div className="relative w-full cursor-default overflow-hidden rounded-lg bg-white text-left shadow-md focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-emerald-300 sm:text-sm">
<Combobox.Input
className="w-full border-none py-2 pl-3 pr-10 text-sm leading-5 text-gray-900 focus:ring-0"
displayValue={(token) => token.name}
onChange={(event) => setQuery(event.target.value)}
/>
<Combobox.Button className="absolute inset-y-0 right-0 flex items-center pr-2">
<SelectorIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</Combobox.Button>
</div>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Combobox.Options className="absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
<a
href="#"
className="relative mb-3 flex select-none items-center space-x-3 py-2 px-4 text-gray-700 hover:bg-neutral-100"
>
<PlusSmIcon className="h-5 w-5" />
<span>Add custom token</span>
</a>
{filteredTokens.length === 0 && query !== '' ? (
<div className="relative select-none py-2 px-4 text-gray-700">
<span>Nothing found..</span>
</div>
) : (
filteredTokens.map((token) => (
<Combobox.Option
key={token.address}
className={({ active }) =>
`relative cursor-default select-none py-2 pl-10 pr-4 ${
active ? 'bg-emerald-600 text-white' : 'text-gray-900'
}`
}
value={token}
>
{({ selected, active }) => (
<div className="flex items-center justify-between">
<div className="flex items-center truncate">
<Image
src={token.logoURI}
alt={token.name}
width="24"
height="24"
className="mr-3"
/>
<span
className={`block truncate ${
selected ? 'font-medium' : 'font-normal'
}`}
>
{token.name}
</span>
</div>
<span
className={`block text-xs text-gray-400 ${
selected ? 'font-medium' : 'font-normal'
} ${active ? 'text-white' : null}`}
>
{token.symbol}
</span>
{selected ? (
<span
className={`absolute inset-y-0 left-0 flex items-center pl-3 ${
active ? 'text-white' : 'text-emerald-600'
}`}
>
<CheckIcon
className="h-5 w-5"
aria-hidden="true"
/>
</span>
) : null}
</div>
)}
</Combobox.Option>
))
)}
</Combobox.Options>
</Transition>
</div>
</Combobox>
</div>
</div>
);
}
It's because you're rendering too much HTML node, your navigator can't paint it.
In order to do what you need, you must use what we call a 'virtual list'.
There are few libraries to virtualize, you're not the first.
Look at for exemple React Window

Animate conditional components in Reactjs to slide in, fade in

I am trying to add some user experience with animations. The problem is the way I have my screen set up. Currently I don't render my sidebar when it's closed, and it looks great and it's responsive, but it seems that I cannot add animations because of the layout I've chosen. As conditionally rendered components don't seem to work with animations.
export default function Layout(props) {
const [open, setOpen] = useState(false);
const isMobile = useMediaQuery({ query: "(max-width: 768px)" });
return (
<div className="relative h-screen w-screen flex">
/// SIDEBAR
{open && (
<section className={"fixed top-0 left-0 bg-white h-screen z-20 w-64 md:relative md:w-1/3 delay-400 duration-500 ease-in-out transition-all transform "
+ (open ? " translate-x-0 " : " translate-x-full ")}></section>
)}
{open && isMobile && (
<div
onClick={(ev) => {
setOpen(false);
}}
className="fixed left-0 mt-0 bg-black bg-opacity-60 w-screen h-screen z-10"
></div>
)}
<div className="relative w-full h-full">
/// TOP BAR
<div className="absolute top-0 h-16 w-full bg-blue-600 flex flex-row items-center p-2 z-5">
<MenuIcon
onClick={(ev) => {
setOpen(!open);
}}
className="text-white"
width={30}
height={30}
></MenuIcon>
</div>
/// CONTENT
<div className="pt-16 h-full w-full overflow-y-auto">{props.children}</div>
</div>
</div>
);
}
Tried using something like this delay-400 duration-500 ease-in-out transition-all transform " + (isOpen ? " translate-x-0 " : " translate-x-full ")
Is there a way to do appearing/ disappearing animations with my current setup or do I have to change the layout entirely?
This is how it currently looks like

Categories