Animation tailwind inside map component - javascript

I'm trying to create an animation inside a map component, but it's not working. Here is the code:
<div className="grid sm:px-0 text-left sm:grid-cols-2 lg:gap-x-16">
{dataProduct.slice(0, ynftMore).map(function (item, i) {
return (
<div
key={item.slug}
className={`md:px-2 lg:px-6 mt-6 lg:mt-8 flex items-center hover:bg-gray-50 hover:rounded-lg transform transition-all duration-300 ease-in-out ${
dataProduct ? 'opacity-100' : 'opacity-0'
}`}
variant="outlined"
onClick={() => {
getDataProductSlug(item.slug).then(() => {
handleClickOpen();
getDataSimilarProduct(item.slug);
if (login !== null) {
getDataUserSlug();
}
});
}}
>
<h1
className="pr-2 font-semibold text-gray-400"
style={{ margin: '0' }}
>
{i + 1}
</h1>
<img
className="w-16 h-16 md:w-24 md:h-24 mx-auto shrink-0 rounded-2xl lg:mx-0 m-none"
alt=""
src={item.logo}
/>
</div>
);
})}
</div>
I expect the animation to appear with the item data. Thanks for helping!

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>

React context throwing TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))

I'm getting the error:
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
whenever I try to manage state from useContext. The idea here is to allow for "tokens" to be initialised at [] on page load, then when set in the TokenListBox component, it is subsequently updated in TokenProviderContext.
TokenProviderContext.tsx:
const TokenProviderContext = React.createContext<any>([]);
export const TokenProvider = ({
children,
}: {
children:
| ReactElement<React.ReactNode, string | JSXElementConstructor<unknown>>[]
| ReactElement<React.ReactNode, string | JSXElementConstructor<unknown>>;
}) => {
const [selectedTokens, setSelectedTokens] = useState<IToken[]>(sampleTokenList);
const contextValue = useMemo(
() => ({
selectedTokens,
setSelectedTokens,
}),
[selectedTokens, setSelectedTokens],
);
return <TokenProviderContext.Provider value={contextValue}>{children}</TokenProviderContext.Provider>;
};
export const useTokenProvider = () => useContext(TokenProviderContext);
TokenListBox.tsx:
export default function TokenListBox({ tokenList }: { tokenList: IToken[] }) {
const [selectedTokens, setSelectedTokens] = useTokenProvider();
useEffect(() => {
if (!selectedTokens) {
setSelectedTokens([]);
}
}, [selectedTokens, setSelectedTokens]);
return (
<Listbox value={selectedTokens} onChange={setSelectedTokens} multiple>
{({ open }) => (
<>
<div className="relative mt-1">
<Listbox.Button
className="relative w-full cursor-default rounded-md border border-gray-300 bg-white
py-2 pl-3 pr-10 text-left shadow-sm focus:border-sky-500 focus:outline-none focus:ring-1 focus:ring-sky-500
sm:text-sm"
>
<span className="flex items-center">
<span className="block truncate">Select Tokens</span>
</span>
<span className="pointer-events-none absolute inset-y-0 right-0 ml-3 flex items-center pr-2">
<ChevronUpDownIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
</span>
</Listbox.Button>
<Transition
show={open}
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
{tokenList.length > 0 && (
<Listbox.Options
className="absolute z-10 mt-1 max-h-56 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"
>
{tokenList.map((token) => (
<Listbox.Option
key={token.symbol}
className={({ active }) =>
classNames(
active ? 'text-white bg-sky-600' : 'text-gray-900',
'relative cursor-default select-none py-2 pl-3 pr-9',
)
}
value={token.name}
>
{({ selected, active }) => (
<>
<div className="flex items-center">
<img src={token.iconSrcUrl} alt="" className="h-6 w-6 flex-shrink-0 rounded-full" />
<span
className={classNames(selected ? 'font-semibold' : 'font-normal', 'ml-3 block truncate')}
>
{token.name}
</span>
</div>
{selected ? (
<span
className={classNames(
active ? 'text-white' : 'text-sky-600',
'absolute inset-y-0 right-0 flex items-center pr-4',
)}
>
<CheckIcon className="h-5 w-5" aria-hidden="true" />
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
)}
</Transition>
</div>
</>
)}
</Listbox>
);
}
When you call useTokenProvider() you would get as result contextValue, which an object not an array, hence the error you are getting.
Assuming TokenListBox is wrapped in TokenProvider, this would work:
const {selectedTokens, setSelectedTokens} = useTokenProvider();

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

Run or execute script after page is loaded with react helmet, react gatsbyjs

i have a blog post page that load content via graphql, in the content are scripts tag of charts.
the problem is that when using it does not load the scripts. Only load the scripts if you refresh the browser.
So i added the scripts to helmet after data loaded but they dont run/load .
Is there a way to "refresh" the dom?
import React, { useEffect,useState, Suspense } from "react"
import { Link, graphql } from "gatsby"
import Img from "gatsby-image"
import Layout from "../components/layout"
import EmbedContainer from "react-oembed-container"
import SEO from "../components/seo"
import { Helmet } from "react-helmet"
const PostContentComponent = React.lazy(() => import('../components/PostContentComponent'));
const BlogPost = ({ data }) => {
const [scripts,setScripts] = useState([])
function getScripts () {
// get all script tags from content
const re = /<script\b[^>]*>[\s\S]*?<\/script\b[^>]*>/g
const results = setScripts(data.strapiPost.content.match(re))
return results
}
console.log('scripts', scripts)
useEffect(() => {
getScripts()
// window.instgrm.Embeds.process()
// window.twttr.widgets.load()
}, [data])
return (
<>
<Layout>
<Helmet>
{scripts ? scripts.map((script)=> {
return script
}): null}
</Helmet>
<SEO title={data.strapiPost.title}/>
<section className="posts-container mx-auto all-blog-content my-5 sm:my-20 px-5">
<h3 className="text-1xl sm:text-3xl font-black mb-3">
{data.strapiPost.title}
</h3>
<div className="autor flex flex-wrap items-start">
<div className="autores flex ">
<div className="autorInfo flex items-start">
<h2 className="text-sm tracking-tighter text-gray-900">
By{" "}
{data.strapiPost.users_permissions_users.length === 1 ? (
<>
<Link className="hover:text-black transition duration-300 ease-in-out text-xs mr-1">
{data.strapiPost.users_permissions_users[0].username}
</Link>{" "}
</>
) : data.strapiPost.users_permissions_users.length === 2 ? (
data.strapiPost.users_permissions_users.map((x, index) => (
<>
<Link
className="hover:text-black transition duration-300 ease-in-out text-xs mr-1"
>
{x.name} {x.lastname}{" "}
{index <
data.strapiPost.users_permissions_users.length - 1
? " &"
: ""}
</Link>
</>
))
) : null}
</h2>
</div>
</div>
{/* LOAD CATEGORIES */}
<div className="md:ml-5">
<ul className="flex flex-nowrap relative ">
{data.strapiPost.categories.map(cat => {
return (
<Link
key={cat.name}
className={`bg-gray-200 py-1 px-2 mr-1 rounded-lg text-black text-xs flex-grow `}
>
{cat.name}
</Link>
)
})}
</ul>
</div>
</div>
<span className="text-gray-600 mr-3 text-xs">
Updated at {new Date(data.strapiPost.updated_at).toDateString()}
</span>
<div className="posts-content py-10">
<Img
alt={data.strapiPost.title}
key={data.strapiPost.featured_image.childImageSharp.fluid.src}
imgStyle={{ objectFit: "contain" }}
fluid={data.strapiPost.featured_image.childImageSharp.fluid}
className="mb-10"
/>
<EmbedContainer markup={data.strapiPost.content}>
<div
dangerouslySetInnerHTML={{ __html: unescape(data.strapiPost.content) }}
/>
</EmbedContainer>
</div>
{/* end of all posts */}
{/* AUTHOR CARD */}
<h3 className="text-2xl font-black text-center my-10">
Read More posts by this Author{" "}
</h3>
</section>
<section className="posts-container mx-auto">
<div
className={`grid grid-cols-1 sm:grid-cols-${data.strapiPost.users_permissions_users.length} md:grid-cols-${data.strapiPost.users_permissions_users.length} xl:grid-cols-${data.strapiPost.users_permissions_users.length} gap-4 my-5`}
>
{data.strapiPost.users_permissions_users.map((user, index) => {
return (
<div
key={index}
className="bg-purple-50 flex flex-col items-center justify-center bg-white p-4 shadow rounded-lg"
>
<div className="inline-flex shadow-lg border border-gray-200 rounded-full overflow-hidden h-40 w-40">
{/* <img
src="https://platformable.com/content/images/2020/03/headshot-profile.png"
alt=""
className="h-full w-full my-0"
/> */}
<Img
alt={data.strapiPost.title}
key={index}
fluid={user.image.childImageSharp.fluid}
className="h-full w-full my-0"
/>
</div>
<h2 className="mt-4 font-bold text-xl">
{user.name} {user.lastname}
</h2>
<h6 className="mt-2 text-sm font-medium">{user.position}</h6>
<p className="text-xs text-gray-500 text-center mt-3">
{user.bio}
</p>
</div>
)
})}
</div>
</section>
</Layout>
</>
)
}
export default BlogPost
export const query = graphql`
query MyPost($slug: String!) {
strapiPost(slug: { eq: $slug }) {
categories {
name
}
content
id
title
users_permissions_users {
id
name
lastname
username
image {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
position
}
updated_at
featured_image {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
}
`
Have you tried something like this:
<Helmet>
{scripts && scripts.map((script)=> <script>{script}</script>)}
</Helmet>
Based on: https://github.com/gatsbyjs/gatsby/issues/6299#issuecomment-402793089
Alternatively, you can use the custom hook approach (useScript).

Categories