I have created a Card component which also involves a list inside, a bit of this code below:
Card.js
export const Card = ({ feature }) => {
*some code*
return (
*some code*
<ul role="list" className="mt-6 space-y-6">
<li className="flex">
<CheckIcon className="flex-shrink-0 w-6 h-6 text-yellow-500" aria-hidden="true" />
<span className="ml-3 text-gray-500">{feature}</span>
</li>
</ul>
)
}
Now I use Card.js in another component ManyCards.js
const pricing = {
tiers: [
{
features: [
'Unlimited products',
'Unlimited subscribers',
'Advanced analytics',
'1-hour, dedicated support response time',
'Marketing automations',
'Custom integrations',
],
}
]
}
export default function ContractInfo() {
return (
<div className={formStep === 0 ? 'block' : 'hidden'}>
<div className="max-w-7xl mx-auto py-24 px-4 sm:px-6 lg:px-8">
<div className="mt space-y-12 lg:space-y-0 lg:grid lg:grid-cols-3 lg:gap-x-8">
{pricing.tiers.map((tier) => (
<Card
feature={tier.features.map((feature) => ())}
/>
))}
</div>
</div>
</div>
}
How do I get all features listed? I assume with map, but how exactly? I am super new to react. These are just bits of code, to demonstrate the issue, I am only stuck with the features.
iterate array using map similar to pricing.tiers just pass tier.features
export const Card = ({ feature }) => {
return (
<>
return (
<ul role="list" className="mt-6 space-y-6">
<li className="flex">
<CheckIcon
className="flex-shrink-0 w-6 h-6 text-yellow-500"
aria-hidden="true"
/>
<span className="ml-3 text-gray-500">{feature}</span>
</li>
</ul>
);
</>
);
};
export function ContractInfo() {
return (
<div className={formStep === 0 ? "block" : "hidden"}>
<div className="max-w-7xl mx-auto py-24 px-4 sm:px-6 lg:px-8">
<div className="mt space-y-12 lg:space-y-0 lg:grid lg:grid-cols-3 lg:gap-x-8">
{pricing.tiers.map((tier) => (
<Card
feature={pricing.tiers.map((tier) => (
<>
{tier.features.map((feature) => (
<Card feature={feature} />
))}
</>
))}
/>
))}
</div>
</div>
</div>
);
}
Related
I'm rendering elements with the map function in react, the problem is that when hovering, the effect is applied to all the elements and what I'm looking for is an individual effect for each card.
This is my code:
const Card = () => {
const [isHovering, setIsHovering] = useState(false);
const handleMouseOver = () => {
setIsHovering(true);
};
const handleMouseOut = () => {
setIsHovering(false);
};
return (
<>
{productsList.map((product) => (
<div key={product.id}>
<div className="relative mb-4" onMouseOver={handleMouseOver} onMouseOut={handleMouseOut}>
<img src={product.img} alt="product" className="w-fit h-fit jshover cursor-pointer" />
{isHovering ? <CardOptions /> : ""}
</div>
<div className="flex justify-center flex-col px-3">
<h3 className="captialize font-sans font-bold text-black mb-3">Adicolor Classics Joggers</h3>
<div className="flex justify-between ">
<span className="capitalize font-normal font-sans text-[#777777]">Dress</span>
<span className="font-sans font-bold">$63.85</span>
</div>
</div>
</div>
))}
</>
)
}
I am iterating an external array of objects with the information of each card.
As seen in the image, I hover my mouse over a card and the "shop now" box appears on all cards.
What would be the best way to do it?
Without iteration of course it worked, but then using React is pointless.
Edit: [SOLVED] The state has to have the index of the iteration of the function. So the conditional rendering has to be conditioned on the index and not on a boolean value.
Like this:
const Card = () => {
const [isHovering, setIsHovering] = useState(-1);
const handleMouseOver = (item) => {
setIsHovering(item);
};
const handleMouseOut = () => {
setIsHovering(-1);
};
return (
<>
{productsList.map((product, index) => (
<div key={product.id}>
<div className="relative mb-4" onMouseOver={() => {
handleMouseOver(index);
}} onMouseOut={handleMouseOut}>
<img src={product.img} alt="product" className="w-fit h-fit jshover cursor-pointer" />
{isHovering === index ? <CardOptions /> : ""}
</div>
<div className="flex justify-center flex-col px-3">
<h3 className="captialize font-sans font-bold text-black mb-3">{product.title}</h3>
<div className="flex justify-between ">
<span className="capitalize font-normal font-sans text-[#777777]">{product.category}</span>
<span className="font-sans font-bold">{product.price}</span>
</div>
</div>
</div>
))}
</>
)
I am working on a portfolio page using React and Tailwind. I am trying to get to where when you hover over each image, it will display the text at the bottom of a single image. Right now when I hover over the image, all text displays on all images. How would I fix this? Also, I know there has to be a way to clean this up, I was trying to get it work first. Thank you for and advice you might have!
const Experience = () => {
const [isHovering, setIsHovering] = useState(false);
const handleMouseOver = () => {
setIsHovering(true);
}
const handleMouseOut = () => {
setIsHovering(false);
}
return (
<div
name="experience"
className="w-full h-screen bg-[#0a192f] text-gray-300"
>
<div className="max-w-[1000px] mx-auto flex flex-col justify-center w-full h-full">
<div>
<p className="text-4xl font-bold inline border-b-4 border-purple-800">
Experience
</p>
<p className="py-4">Technologies I have worked with</p>
</div>
<div className="w-full grid grid-cols-2 sm:grid-cols-4 gap-4 text-center py-8">
<div className="shadow-md shadow-[#040c16] hover:scale-110 duration-500">
<img
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
className="w-20 mx-auto"
src={CssLogo}
alt="Css Logo"
/>
{isHovering ? <p className="font-bold">CSS</p> : ""}
</div>
<div className="shadow-md shadow-[#040c16] hover:scale-110 duration-500">
<img
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
className="w-20 mx-auto"
src={HtmlLogo}
alt="HTML logo"
/>
{isHovering ? <p className="font-bold">HTML</p> : handleMouseOut}
</div>
<div className="shadow-md shadow-[#040c16] hover:scale-110 duration-500">
<img
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
className="w-20 mx-auto"
src={JavaScriptLogo}
alt="Js Logo"
/>
{isHovering ? (
<p className="font-bold">JavaScript</p>
) : (
handleMouseOut
)}
</div>
<div className="shadow-md shadow-[#040c16] hover:scale-110 duration-500">
<img
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
className="w-20 mx-auto"
src={MongoLogo}
alt="Mongo Logo"
/>
{isHovering ? (
<p className="font-bold">Mongo DB</p>
) : (
''
)}
</div>
<div className="shadow-md shadow-[#040c16] hover:scale-110 duration-500">
<img
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
className="w-20 mx-auto"
src={MysqlLogo}
alt="Mysql Logo"
/>
{isHovering ? (
<p className="font-bold">MySQL</p>
) : (
''
)}
</div>
<div className="shadow-md shadow-[#040c16] hover:scale-110 duration-500">
<img
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
className="w-20 mx-auto"
src={NodeLogo}
alt="Node Logo"
/>
{isHovering ? (
<p className="font-bold">Node JS</p>
) : (
''
)}
</div>
You have lots of text elements, but only one state value:
const [isHovering, setIsHovering] = useState(false);
So either all of them are "hovering" or all of them are "not hovering". Instead of a boolean, you might use some kind of identifier. For example:
const [hoveringID, setHoveringID] = useState();
And update the state to an identifier:
const handleMouseOver = (id) => {
setHoveringID(id);
}
const handleMouseOut = () => {
setHoveringID(undefined);
}
And pass some ID to those handlers:
onMouseOver={() => handleMouseOver(1)}
(Use a different ID for each element, of course.) And use that state to determine if that element is "hovering":
{hoveringID === 1 ? <p className="font-bold">CSS</p> : ""}
Taking it a step further, this all becomes much easier if you refactor all of that repeated code. Create data for your component:
const sections = [
{
id: 1,
src: CssLogo,
alt: "Css Logo",
hoverContent: "CSS"
},
//etc...
]
And just map over that data:
<div className="w-full grid grid-cols-2 sm:grid-cols-4 gap-4 text-center py-8">
{
sections.map(section => (
<div className="shadow-md shadow-[#040c16] hover:scale-110 duration-500">
<img
onMouseOver={() => handleMouseOver(section.id)}
onMouseOut={handleMouseOut}
className="w-20 mx-auto"
src={section.src}
alt={section.alt}
/>
{hoveringID === section.id ? <p className="font-bold">{section.hoverContent}</p> : ""}
</div>
))
}
</div>
I am implementing authentication on nextjs strapi graphql and I want to redirect user once he registers or logins or theres is jwt token in cookies but when I login. its not redirecting using router.push method, I am also checking in other pages if user exist in cookies but use`Effect not working Here is my code example
System Information
4.1.11:
Macos:
Mysql:
14.17.00:
6.14.13:
1.22.19:
import { useContext, useEffect, useState } from "react";
import Image from "next/image";
import Link from "next/link";
import { useMutation } from "#apollo/client";
import { LOGIN_USER } from "../../gql/mutations";
import { userContext } from "../../context/wrapppers/UserWrapper";
import { setUserAction } from "../../context/actions/user-actions";
import { SIGN_IN } from "../../context/actions/action-types";
import { useRouter } from "next/router";
function login() {
const router = useRouter();
const { user, dispatchUser } = useContext(userContext);
const [credentials, setCredentials] = useState({});
useEffect(() => {
if (user !== "" && user !== undefined) {
router.push("/account");
}
}, []);
const [loginUser, { loading, error, data }] = useMutation(LOGIN_USER);
useEffect(() => {
if (data) {
dispatchUser(
setUserAction(
{
token: data.login.jwt,
username: data.login.user.username,
id: data.login.user.id,
email: data.login.user.email,
},
SIGN_IN
)
);
}
}, [data]);
if (loading) return <h1>logging in...</h1>;
if (error) return <h1>{error.message}</h1>;
console.log("user from login page", user);
const handleChange = (e) => {
setCredentials({
...credentials,
[e.target.name]: e.target.value,
});
};
const handleLogin = (e) => {
if (typeof window === "undefined") {
return;
}
e.preventDefault();
loginUser({
variables: {
input: credentials,
},
});
};
return (
<div className="h-screen bg-slate-50 flex justify-center items-center w-full">
{error && <div>{error.message}</div>}
<form onSubmit={handleLogin}>
<div className="bg-white px-10 py-8 rounded-xl w-screen shadow-md max-w-sm">
<Image
src={require("../../public/Img/logo.png")}
height={50}
objectFit="contain"
className="h-14 mb-4 mx-auto"
alt=""
/>
<div className="space-y-4">
<h1 className="text-center text-2xl font-semibold text-gray-600">
Login
</h1>
<div>
<label
for="email"
className="block mb-1 text-gray-600 font-semibold"
>
Email or Username
</label>
<input
name="identifier"
onChange={handleChange}
type="text"
required
className="bg-indigo-50 px-4 py-2 outline-none rounded-md w-full"
/>
</div>
<div>
<label
for="password"
className="block mb-1 text-gray-600 font-semibold"
>
Password
</label>
<input
name="password"
onChange={handleChange}
type="text"
required
className="bg-indigo-50 px-4 py-2 outline-none rounded-md w-full"
/>
</div>
</div>
<button
type="submit"
className="mt-4 w-full bg-yellow-500 font-semibold py-2 rounded-md tracking-wide"
>
Login
</button>
<Link href="account/register">
<h3 className="mt-2 cursor-pointer">Or Create an account</h3>
</Link>
</div>
</form>
</div>
);
}
export default login;
function index() {
const router = useRouter();
const { user, dispatchUser } = useContext(userContext);
const [getUserOrders, { loading, error, data }] = useLazyQuery(USER_ORDERS);
useEffect(() => {
if (user) {
getUserOrders({
variables: {
filters: {
user: {
id: {
eq: user.id,
},
},
status: {
ne: "rejected",
},
},
},
});
} else {
router.push("/account/login");
}
}, [user]);
if (error) return <div>{error.message}</div>;
if (loading) return <div>Loading ...</div>;
const handleLogout = () => {
router.push("/account/login");
dispatchUser(setUserAction(user, SIGN_OUT));
};
return (
<div>
<section className="py-5 sm:py-7 bg-gray-100">
<div className="container max-w-screen-xl mx-auto px-4">
Home/Account
</div>
</section>
<section className="py-10">
<div className="container max-w-screen-xl mx-auto px-4">
<div className="flex flex-col md:flex-row -mx-4">
<aside className="md:w-1/3 lg:w-1/4 px-4">
<ul>
<li>
<Link href="/account">
<span className="block px-3 py-2 text-primary bg-gray-100 hover:bg-orange-100 rounded-md">
Account
</span>
</Link>
</li>
<li>
<div
className="cursor-pointer flex items-center"
onClick={handleLogout}
>
<IoIosLogOut size="20" className="mr-2" />
<span>Log out</span>
</div>
</li>
</ul>
</aside>
<main className="md:w-2/3 lg:w-3/4 px-4">
<article className="border border-gray-200 bg-white shadow-sm rounded mb-5 p-3 lg:p-5">
<figure className="flex items-start sm:items-center">
<AiOutlineUser size="50" />
<figcaption>
<h5 className="font-semibold text-lg">
Hi {user.username}
</h5>
<p>Email: {user.email}</p>
</figcaption>
</figure>
<hr className="my-4" />
<h3 className="text-xl font-semibold mb-5">Order History</h3>
{data && data.orders.data.length !== 0 ? (
data.orders.data.map(({ id, attributes }, orderIndex) => (
<article
key={id}
className="p-3 lg:p-5 mb-5 bg-white border border-blue-600 rounded-md"
>
<header className="lg:flex justify-between mb-4">
<div className="mb-4 lg:mb-0">
<p className="font-semibold">
<span>Order ID: #{id} </span>
<span className="text-green-500">
{" "}
• {attributes.status}{" "}
</span>
</p>
<p className="text-gray-500">
{" "}
{new Date(
attributes.createdAt
).toLocaleDateString()}
</p>
</div>
</header>
<hr className="my-4" />
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-2">
{attributes.products.data.map(
({ id, attributes }, productIndex) => (
<Link href={`/shop/${attributes.slug}`}>
<figure
key={id}
className="flex flex-row mb-4 cursor-pointer"
>
<div>
<Image
src={`${
BACKEND_URL +
attributes.media.data[0].attributes.url
}`}
width={80}
height={80}
objectFit="cover"
className="rounded"
/>
</div>
<figcaption className="ml-3">
<p className="text-gray-600">
{attributes.name}
</p>
<p className="mt-1 font-semibold">
{
data.orders.data[orderIndex].attributes
.details[productIndex].quantity
}{" "}
x ${attributes.price}
</p>
</figcaption>
</figure>
</Link>
)
)}
</div>
</article>
))
) : (
<EmptyState
title="You have not yet ordered"
subtitle="Choose some products to order"
image={EmptyOrder}
btnText="Go to shop"
btnText2="Go Home"
btnLink="/shop"
btnLink2="/"
/>
)}
</article>
</main>
</div>
</div>
</section>
</div>
);
}
export default index;
I am quite new in nextjs and graphql any suggesstion highly appreciated!
this is the onclick function
export function changeColorButton() {
document.getElementById("friendDiv").style.background = "grey";
}
this is the output file. I want every button to be clickable and give background grey
{data.projects.map((project, key) => {
return (
<div id="friendDiv" className="relative">
<div key={key} className="flex flex-row items-center space-x-6 mb-6">
<img src={project.image} />
<div>
<h1 key={key} class=" text-xl font-bold">
{project.name}
</h1>
</div>
<button
className="absolute right-10 bg-bgButtonAddPeople p-2"
onClick={changeColorButton}
>
Legg til
</button>
</div>
</div>
);
});
}
You would just need to componentize the div element that is being mapped. So you can follow an approach like this.
Each FriendDiv element would have its own instance of changeColorButton, so it would apply the color to its own element.
FriendDiv.js
const FriendDiv = ({ key, project }) => {
const [isGrey, setIsGrey] = useState(false);
const changeColorButton = () => {
setIsGrey(!isGrey);
};
return (
<div
style={{ backgroundColor: isGrey ? 'grey' : 'default-color}}
id="friendDiv"
className="relative"
>
<div key={key} className="flex flex-row items-center space-x-6 mb-6">
<img src={project.image} />
<div>
<h1 key={key} class=" text-xl font-bold">
{project.name}
</h1>
</div>
<button
className="absolute right-10 bg-bgButtonAddPeople p-2"
onClick={changeColorButton}
>
Legg til
</button>
</div>
</div>
);
};
App.js
const App = () => {
return data.projects.map((project, key) => {
return <FriendDiv project={project} key={key} />;
});
};
I want to store the return value of the map into a variable but I'm getting this error of expected ) or const is reserve value. I can do this on react.js but I'm having this issue in next.js
<div className='w-3/5 flex flex-wrap justify-between mx-auto pt-24'>
{props.map((prop) => (
let rating = `${prop.review_scores.review_scores_accuracy}`;
<div
key={prop._id}
class='max-w-sm overflow-hidden shadow-xl flex-shrink'
>
<img
class='w-full'
src={prop.images.picture_url}
alt='Mountain'
/>
<div class='px-6 py-4'>
<h2 class='text-md font-bold mb-1'>{prop.name}</h2>
<p class='text-gray-700 text-base truncate'>
{prop.description}
</p>
<div>
{[
...Array(fullName),
].map((star, index) => {
return (
<FontAwesomeIcon
key={index}
icon={faStar}
className='w-4 h-4 fill-current text-indigo-900'
/>
);
})}
</div>
</div>
</div>
))}
</div>
Replace this part of code:
{props.map((prop) => (
let rating = `${prop.review_scores.review_scores_accuracy}`;
<div
key={prop._id}
class='max-w-sm overflow-hidden shadow-xl flex-shrink'
>
with:
{props.map((prop) => {
let rating = `${prop.review_scores.review_scores_accuracy}`;
return (
<div
key={prop._id}
class='max-w-sm overflow-hidden shadow-xl flex-shrink'
>
[REST_OF_CODE]
)}