react useRef in carousel - javascript

I have a carousel that prints out a lists of data, 5 in total,
the issue is when I click on the next of any of the carousel buttons,
only the bottom carousel updates.
Any suggestions?
Here is my react tailwind code :
// query all available genres and for it create a listview row of the content
import { useState, useRef, useEffect } from "react";
import React from "react";
import ShowList from "./showlist.json";
import "./carousel.css";
import data from "./data.json";
export default function Genre() {
const maxScrollWidth = useRef(0);
const [currentIndex, setCurrentIndex] = useState(0);
const listCarousel = useRef(0);
const containerCarousel = useRef(0);
const movePrev = () => {
if (currentIndex > 0) {
setCurrentIndex((prevState) => prevState - 1);
}
};
const moveNext = () => {
if (
listCarousel.current !== null &&
listCarousel.current.offsetWidth * currentIndex <= maxScrollWidth.current
) {
setCurrentIndex((prevState) => prevState + 1);
}
};
const isDisabled = (direction) => {
if (direction === "prev") {
return currentIndex <= 0;
}
if (direction === "next" && listCarousel.current !== null) {
return (
listCarousel.current.offsetWidth * currentIndex >= maxScrollWidth.current
);
}
return false;
};
useEffect(() => {
if (listCarousel !== null && listCarousel.current !== null) {
listCarousel.current.scrollLeft = listCarousel.current.offsetWidth * currentIndex;
}
}, [currentIndex]);
useEffect(() => {
maxScrollWidth.current = listCarousel.current
? listCarousel.current.scrollWidth - listCarousel.current.offsetWidth
: 0;
}, []);
const DisplayData = ShowList.map((value, itemIndex) => {
let imageList = value.Shows.map((item) => {
return item;
});
return (
<section>
<div
ref={containerCarousel}
className="carousel my-12 mx-auto"
>
<h1 className="text-3xl leading-8 font-bold mb-12 text-slate-700">
{value.name}
</h1>
<div
className="relative overflow-hidden">
<div className="flex justify-between absolute top left w-full h-full">
<button
onClick={movePrev}
className="hover:bg-blue-900/75 text-white w-10 h-full text-center opacity-75 hover:opacity-100 disabled:opacity-25 disabled:cursor-not-allowed z-10 p-0 m-0 transition-all ease-in-out duration-300"
disabled={isDisabled("prev")}
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-12 w-20 -ml-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M15 19l-7-7 7-7"
/>
</svg>
<span className="sr-only">Prev</span>
</button>
<button
onClick={moveNext}
className="hover:bg-blue-900/75 text-white w-10 h-full text-center opacity-75 hover:opacity-100 disabled:opacity-25 disabled:cursor-not-allowed z-10 p-0 m-0 transition-all ease-in-out duration-300"
disabled={isDisabled("next")}
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-12 w-20 -ml-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M9 5l7 7-7 7"
/>
</svg>
<span className="sr-only">Next</span>
</button>
</div>
<div
ref={listCarousel}
className="carousel-container relative flex gap-1 overflow-hidden scroll-smooth snap-x snap-mandatory touch-pan-x z-0"
>
{imageList.map((img, index) => {
return (
<ul>
<li
key={index}
className="carousel-item text-center relative w-64 h-64 snap-start"
>
<a
href={img.link}
className="h-full w-full aspect-square block bg-origin-padding bg-left-top bg-cover bg-no-repeat z-0"
style={{ backgroundImage: `url(${img.image || ""})` }}
>
<img
src={img.image || ""}
alt={img.title}
className="w-full rounded aspect-square hidden"
/>
</a>
<a
href={img.link}
className="h-full w-full aspect-square block absolute top-0 left-0 transition-opacity duration-300 opacity-0 hover:opacity-100 bg-blue-800/75 z-10"
>
<h3 className="text-white py-6 px-3 mx-auto text-xl">
{img.title}
</h3>
</a>
</li>
</ul>
);
})}
</div>
</div>
</div>
</section>
);
});
return <div>{DisplayData}</div>;
}
here is my data json file:
https://drive.google.com/file/d/1G0wInErDa2bUHGjn-TNDfTVXJru0QlaY/view?usp=sharing

Related

function interpolations in a mapped component

below is couple of function (its inside a fictional component that's mapped over) , so i need help in a way to make this functions more dynamic . i appreciate the feedback
import { FC } from "react";
import {
questionOption1Variant,
questionOption2Variant,
dividerVariant,
} from "../animations/questionAnimation";
import { motion } from "framer-motion";
import { useAppSelector, useAppDispatch } from "../App";
import { countriesActions1 } from "../redux/fetch1";
import { countriesActions2 } from "../redux/fetch2";
import { useNavigate } from "react-router-dom";
import ResultBox1 from "./ResultBox1";
import ResultBox2 from "./ResultBox2";
const Question1: FC = () => {
const country = useAppSelector((state) => state.countries1);
const dispatch = useAppDispatch();
const navigate = useNavigate();
const firstChoiseHandler = () => {
dispatch(countriesActions1.chooseCountry1());
dispatch(countriesActions2.setQuestion());
setTimeout(() => navigate("/q2"), 2500);
};
const secondChoiseHandler = () => {
dispatch(countriesActions1.chooseCountry2());
dispatch(countriesActions2.setQuestion());
setTimeout(() => navigate("/q2"), 2500);
};
return (
<div className="grid grid-cols-3 h-screen w-screen">
<motion.div
variants={questionOption1Variant}
initial="hidden"
animate="visible"
exit="exit"
className="flex flex-col justify-center items-center pl-52"
>
<div>
<img
src={country.questionOption1.image}
alt="flag"
className={
country.correctAnswer1
? `rounded-full border-primary-200 border-8 h-80 w-80`
: `rounded-full border-red-500 border-8 h-80 w-80 transition-all duration-300 ease-in-out`
}
/>
</div>
<div className="my-5">
<h1 className="text-3xl font-rubik font-semibold text-secondary-200 uppercase">
{country.questionOption1.title}
</h1>
</div>
<button
className="my-5 mdbt primarybt uppercase"
onClick={firstChoiseHandler}
>
Correct Answer
</button>
<ResultBox1 country={country} />
</motion.div>
<div className="relative">
<svg
version="1.1"
id="Capa_1"
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
viewBox="0 0 14.707 20.3"
className="enable-background:new 0 0 18.707 18.707;"
>
<motion.g
variants={dividerVariant}
initial="hidden"
animate="visible"
>
<rect
x="6.275"
y="0"
className="fill-black"
width="0.5"
height="20.3"
/>
</motion.g>
</svg>
</div>
<motion.div
variants={questionOption2Variant}
initial="hidden"
animate="visible"
exit="exit"
className="flex flex-col justify-center items-center pr-52 "
>
<div>
<img
src={country.questionOption2.image}
alt="flag"
className={
country.correctAnswer2
? `rounded-full border-primary-200 border-8 h-80 w-80`
: `rounded-full border-red-500 border-8 h-80 w-80 transition-all duration-300 ease-in-out`
}
/>
</div>
<div className="my-5">
<h1 className="text-3xl font-rubik font-semibold text-secondary-200 uppercase">
{country.questionOption2.title}
</h1>
</div>
<button
className="my-5 mdbt primarybt uppercase"
onClick={secondChoiseHandler}
>
Correct Answer
</button>
<ResultBox2 country={country} />
</motion.div>
</div>
);
};
export default Question1;
in above i wanted the second import to be dynamic so it will only add +1 to the fist import instead of hard coding it as 2
import { countriesActions1 } from "../redux/fetch1";
import { countriesActions2 } from "../redux/fetch2";
in below i wanted the number 1 & 2 to be dynamic , lets say i have data (which an array of objects) each object contains an id of 1 ,2 ,3 ...ect , how i can make it dynamic based on that
const country = useAppSelector((state) => state.countries1);
const firstChoiseHandler = () => {
dispatch(countriesActions1.chooseCountry1());
dispatch(countriesActions2.setQuestion());
setTimeout(() => navigate("/q2"), 2500);
};

Adding transform to carousel element breaks scroll

I recently came across this carousel Tailwind component (https://codesandbox.io/s/react-multi-item-carousel-uvmchp?file=/src/carousel.jsx).
I wanted the carousel items to enlargen on hover, so I made a change (namely adding hover:scale-125 transform-gpu transition duration-150 ease-in-out and removing overflow-hidden), but in doing so the left and right arrows of the carousel no longer work.
How can I fix this?
My code is here: https://codesandbox.io/s/react-multi-item-carousel-forked-jebmii?file=/src/carousel.jsx:0-4494
import { useState, useRef, useEffect } from "react";
import data from "./data.json";
const CollectionCarousel = () => {
const maxScrollWidth = useRef(0);
const [currentIndex, setCurrentIndex] = useState(0);
const carousel = useRef(null);
const movePrev = () => {
if (currentIndex > 0) {
setCurrentIndex((prevState) => prevState - 1);
}
};
const moveNext = () => {
if (carousel.current.offsetWidth * currentIndex <= maxScrollWidth.current) {
setCurrentIndex((prevState) => prevState + 1);
}
};
const isDisabled = (direction) => {
if (direction === "prev") {
return currentIndex <= 0;
}
if (direction === "next" && carousel.current !== null) {
return (
carousel.current.offsetWidth * currentIndex >= maxScrollWidth.current
);
}
return false;
};
useEffect(() => {
if (carousel !== null && carousel.current !== null) {
carousel.current.scrollLeft = carousel.current.offsetWidth * currentIndex;
}
}, [currentIndex]);
useEffect(() => {
maxScrollWidth.current = carousel.current
? carousel.current.scrollWidth - carousel.current.offsetWidth
: 0;
}, []);
return (
<div className="carousel my-12 mx-auto">
<div className="relative">
<div className="flex justify-between absolute top left w-full h-full">
<button
onClick={movePrev}
className="hover:bg-blue-900/75 text-white w-10 h-full text-center opacity-75 hover:opacity-100
disabled:opacity-25 disabled:cursor-not-allowed z-10 p-0 m-0 transition-all ease-in-out duration-300"
disabled={isDisabled("prev")}
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-12 w-20 -ml-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M15 19l-7-7 7-7"
/>
</svg>
<span className="sr-only">Prev</span>
</button>
<button
onClick={moveNext}
className="hover:bg-blue-900/75 text-white w-10 h-full text-center opacity-75 hover:opacity-100
disabled:opacity-25 disabled:cursor-not-allowed z-10 p-0 m-0 transition-all ease-in-out duration-300"
disabled={isDisabled("next")}
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-12 w-20 -ml-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M9 5l7 7-7 7"
/>
</svg>
<span className="sr-only">Next</span>
</button>
</div>
<div
ref={carousel}
className="carousel-container relative flex gap-1 scroll-smooth snap-x snap-mandatory touch-pan-x z-0"
>
{data.resources.map((resource, index) => {
return (
<div
key={index}
className="carousel-item text-center relative w-64 h-64 snap-start hover:scale-125 transform-gpu
transition duration-150 ease-in-out"
>
<a
href={resource.link}
className="h-full w-full aspect-square block bg-origin-padding bg-left-top bg-cover bg-no-repeat z-0"
style={{ backgroundImage: `url(${resource.imageUrl || ""})` }}
>
<img
src={resource.imageUrl || ""}
alt={resource.title}
className="w-full aspect-square hidden"
/>
</a>
<a
href={resource.link}
className="h-full w-full aspect-square block absolute top-0 left-0 transition-opacity
duration-300 opacity-0 hover:opacity-100 bg-blue-800/75 z-10"
>
<h3 className="text-white py-6 px-3 mx-auto text-xl">
{resource.title}
</h3>
</a>
</div>
);
})}
</div>
</div>
</div>
);
};
export default CollectionCarousel;

How to persist the value of state variables after window reloads in nextJS?

Intro
I am designing an e-commerce platform in nextJS. It consists of Tshirts page like this .
After clicking any of the four t-shirts, i went to that particular t-shirt page in slug.js file, where the page looks like this.
This is where I am facing issue.
Issue
As you can see that the URL of the black t-shirt page is
http://localhost:3000/products/wear-the-chess-formula-S-Black
which is correct, but after that if I select any of the color and size variant, say (Green,M), It does not get reflected in the URL after the reload . You can also see the top-left on the image below. Also after the reload I see the black t-shirt image again.
For this functionality , I had built the following function.
const refreshVariant = (newsize, newcolor) => {
let url = `http://localhost:3000/products/${colorSizeSlug[newcolor][newsize]["slug"]}`;
//console.log("url = ",url, "newcolor - ",newcolor, "newsize - ", newsize)
//console.log("newvaraint -", colorSizeSlug)
window.location = url;
};
What I thought?
I think that clicking the colour button & size dropdown option , the value of color&size changes but then after reloads, it again goes to its initial value.
Live Behaviour
what i want?
I want to retain the values of these two state variables color & size, so that every time we select the color, the same color dot get highlighted and same gets reflected in URL. For example if I select the Green color and M size, then Green color dot should get highlighted with border and this URL should come
http://localhost:3000/products/wear-the-chess-formula-M-Green
code
The file responsible for this is slug.js
import React, { useState } from "react";
import { useRouter } from "next/router";
import mongoose from "mongoose";
import Product from "../../models/Product";
//colosizeSlug :
// {
// Black: {S: {slug: "wear-the-chess-formula-1"}},
// Blue: {M: {slug: "wear-the-chess-formula-2"}},
// Green: {L: {slug: "wear-the-chess-formula-3"}},
// Red: {XL: {slug: "wear-the-chess-think-1"} ,XXL: {slug: "wear-the-chess-think-2"}}
// }
// MY LOGS
//date - 17-4-22
//issue of setColor & setSize is resolved but now the window reload functon disabled. It is beacuse when the page reloads , the state value of color and size revert back to the its initial value & not the current value. That's why you can see the updated url is not displayed in chrome tab.
const Slug = ({ addToCart, all_Tshirts, colorSizeSlug }) => {
//console.log(all_Tshirts, colorSizeSlug);
//console.log("keys = ",Object.keys(colorSizeSlug["Red"]))
const router = useRouter();
const { slug } = router.query;
const [pin, setPin] = useState();
const [isAvailable, setIsAvailable] = useState();
const [color, setColor] = useState(all_Tshirts[0].color);
const [size, setSize] = useState(all_Tshirts[0].size);
console.log("size =", size, " color = ", color);
const checkservicibilty = async () => {
let pins = await fetch("http://localhost:3000/api/pincode");
let pinjson = await pins.json();
//console.log(pin, pinjson);
if (pinjson.includes(pin)) {
setIsAvailable(true);
//console.log("Available");
} else {
setIsAvailable(false);
//console.log("NOt");
}
};
const onChangePin = (e) => {
setPin(e.target.value);
};
const refreshVariant = (newsize, newcolor) => {
let url = `http://localhost:3000/products/${colorSizeSlug[newcolor][newsize]["slug"]}`;
//console.log("url = ",url, "newcolor - ",newcolor, "newsize - ", newsize)
//console.log("newvaraint -", colorSizeSlug)
window.location = url;
};
return (
<>
<section className="text-gray-600 body-font overflow-hidden">
<div className="container px-5 py-16 mx-auto">
<div className="lg:w-4/5 mx-auto flex flex-wrap">
<img
alt="ecommerce"
className="lg:w-1/2 w-full h-80 lg:h-[36rem] object-cover object-top rounded"
src={`${colorSizeSlug[color][size]["url"]}`}
/>
<div className="lg:w-1/2 w-full lg:pl-10 lg:py-6 mt-6 lg:mt-0">
<h2 className="text-sm title-font text-gray-500 tracking-widest">
CHESS WEAR
</h2>
<h1 className="text-gray-900 text-3xl title-font font-medium mb-1">
Men&apos;s Chess Formula T-Shirt ( L-Black )
</h1>
<div className="flex mb-4">
<span className="flex items-center">
.
.
.
<span className="text-gray-600 ml-3">4 Reviews</span>
</span>
<span className="flex ml-3 pl-3 py-2 border-l-2 border-gray-200 space-x-2s">
.
.
.
</span>
</div>
<p className="leading-relaxed">
Fam locavore kickstarter distillery. Mixtape chillwave tumeric
sriracha taximy chia microdosing tilde DIY. XOXO fam indxgo
juiceramps cornhole raw denim forage brooklyn. Everyday carry +1
seitan poutine tumeric. Gastropub blue bottle austin listicle
pour-over, neutra jean shorts keytar banjo tattooed umami
cardigan.
</p>
<div className="flex mt-6 items-center pb-5 border-b-2 border-gray-100 mb-5">
<div className="flex">
<span className="mr-3">Color</span>
{Object.keys(colorSizeSlug).includes("Red") &&
Object.keys(colorSizeSlug["Red"]).includes(size) && (
<button
onClick={() => {
refreshVariant(size, "Red");
setColor("Red");
}}
className={`border-2 bg-red-600 rounded-full w-6 h-6 focus:outline-none ${
color === "Red" ? "border-black" : "border-gray-300"
}`}
></button>
)}
{Object.keys(colorSizeSlug).includes("Green") &&
Object.keys(colorSizeSlug["Green"]).includes(size) && (
<button
onClick={() => {
refreshVariant(size, "Green");
setColor("Green");
}}
className={`border-2 ml-1 bg-green-600 rounded-full w-6 h-6 focus:outline-none ${
color === "Green" ? "border-black" : "border-gray-300"
}`}
></button>
)}
{Object.keys(colorSizeSlug).includes("Black") &&
Object.keys(colorSizeSlug["Black"]).includes(size) && (
<button
onClick={() => {
refreshVariant(size, "Black");
setColor("Black");
}}
className={`border-2 ml-1 bg-black rounded-full w-6 h-6 focus:outline-none ${
color === "Black" ? "border-black" : "border-gray-300"
}`}
></button>
)}
{Object.keys(colorSizeSlug).includes("White") &&
Object.keys(colorSizeSlug["White"]).includes(size) && (
<button
onClick={() => {
refreshVariant(size, "White");
setColor("White");
}}
className={`border-2 bg-white rounded-full w-6 h-6 focus:outline-none ${
color === "White" ? "border-black" : "border-gray-300"
}`}
></button>
)}
{Object.keys(colorSizeSlug).includes("Yellow") &&
Object.keys(colorSizeSlug["Yellow"]).includes(size) && (
<button
onClick={() => {
refreshVariant(size, "Yellow");
setColor("Yellow");
}}
className={`border-2 bg-yellow-500 rounded-full w-6 h-6 focus:outline-none ${
color === "Yellow"
? "border-black"
: "border-gray-300"
}`}
></button>
)}
{Object.keys(colorSizeSlug).includes("Purple") &&
Object.keys(colorSizeSlug["Purple"]).includes(size) && (
<button
onClick={() => {
refreshVariant(size, "Purple");
setColor("Purple");
}}
className={`border-2 bg-purple-600 rounded-full w-6 h-6 focus:outline-none ${
color === "Purple"
? "border-black"
: "border-gray-300"
}`}
></button>
)}
{Object.keys(colorSizeSlug).includes("Maroon") &&
Object.keys(colorSizeSlug["Maroon"]).includes(size) && (
<button
onClick={() => {
refreshVariant(size, "Maroon");
setColor("Maroon");
}}
className={`border-2 bg-rose-700 rounded-full w-6 h-6 focus:outline-none ${
color === "Maroon"
? "border-black"
: "border-gray-300"
}`}
></button>
)}
{Object.keys(colorSizeSlug).includes("Blue") &&
Object.keys(colorSizeSlug["Blue"]).includes(size) && (
<button
onClick={() => {
refreshVariant(size, "Blue");
setColor("Blue");
}}
className={`border-2 bg-blue-500 rounded-full w-6 h-6 focus:outline-none ${
color === "Blue" ? "border-black" : "border-gray-300"
}`}
></button>
)}
</div>
<div className="flex ml-6 items-center">
<span className="mr-3">Size</span>
<div className="relative">
<select
value={size}
onChange={(e) => {
refreshVariant(e.target.value, color);
setSize(e.target.value);
}}
className="rounded border appearance-none border-gray-300 py-2 focus:outline-none focus:ring-2 focus:ring-blue-200 focus:border-blue-500 text-base pl-3 pr-10"
>
{Object.keys(colorSizeSlug[color]).includes("S") && (
<option value={"S"}>S</option>
)}
{Object.keys(colorSizeSlug[color]).includes("M") && (
<option value={"M"}>M</option>
)}
{Object.keys(colorSizeSlug[color]).includes("L") && (
<option value={"L"}>L</option>
)}
{Object.keys(colorSizeSlug[color]).includes("XL") && (
<option value={"XL"}>XL</option>
)}
{Object.keys(colorSizeSlug[color]).includes("XXL") && (
<option value={"XXL"}>XXL</option>
)}
</select>
<span className="absolute right-0 top-0 h-full w-10 text-center text-gray-600 pointer-events-none flex items-center justify-center">
<svg
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
className="w-4 h-4"
viewBox="0 0 24 24"
>
<path d="M6 9l6 6 6-6"></path>
</svg>
</span>
</div>
</div>
</div>
<div className="flex">
<span className="title-font font-medium text-2xl text-gray-900">
₹499
</span>
<button
onClick={() =>
addToCart(
slug,
1,
499,
"wear the chess(XL, Red)",
"XL",
"Red"
)
}
className="flex ml-auto md:ml-24 text-sm lg:text-base text-white bg-blue-500 border-0 py-2 px-4 lg:px-6 focus:outline-none hover:bg-blue-600 rounded"
>
Add to Cart
</button>
<button className="flex ml-1 md:ml-2 text-white text-sm lg:text-base bg-blue-500 border-0 py-2 px-4 lg:px-6 focus:outline-none hover:bg-blue-600 rounded">
Buy Now
</button>
<button className="rounded-full w-10 h-10 bg-gray-200 p-0 border-0 inline-flex items-center justify-center text-gray-500 ml-4 md:ml-6">
<svg
fill="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
className="w-5 h-5"
viewBox="0 0 24 24"
>
<path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z"></path>
</svg>
</button>
</div>
<div className="pin mt-6 space-x-2 flex text-sm">
<input
type="text"
id="name"
name="name"
onChange={onChangePin}
placeholder="Enter Pincode Here"
className="w-3/5 md:w-2/5 bg-gray-100 bg-opacity-50 rounded border border-gray-300 focus:border-blue-500 focus:bg-white focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"
/>
<button
onClick={checkservicibilty}
className="text-white bg-blue-500 border-0 py-2 px-6 focus:outline-none hover:bg-blue-600 rounded"
>
Check
</button>
</div>
{isAvailable != null ? (
isAvailable ? (
<div className="text-sm mt-4 text-green-600">
Yay ! This pincode is serviceable .
</div>
) : (
<div className="text-sm mt-4 text-red-600">
Sorry ! We do not deliver to this pincode yet .
</div>
)
) : (
<div></div>
)}
</div>
</div>
</div>
</section>
</>
);
};
// taking all the variants of a tshirt/hoodies of same title from the slug
// for eg, if slug=wear-chess-think-2, then it will give all the 'Chess-Think Tshirts'=title tshirts in variant-array
export async function getServerSideProps(context) {
if (!mongoose.connections[0].readyState) {
await mongoose.connect(process.env.MONGO_URI);
}
let product = await Product.findOne({ slug: context.query.slug });
let all_Tshirts = await Product.find({ title: product.title });
//all tshirts of same title with the given 'slug'
//console.log("all -",all_Tshirts)
let colorSizeSlug = {};
//eg: {'Red': {'XL':'wear-the-chess-king-1}}
for (let item of all_Tshirts) {
if (Object.keys(colorSizeSlug).includes(item.color)) {
colorSizeSlug[item.color][item.size] = { slug: item.slug, url: item.img };
} else {
colorSizeSlug[item.color] = {};
colorSizeSlug[item.color][item.size] = { slug: item.slug, url: item.img };
}
}
return {
props: {
all_Tshirts: JSON.parse(JSON.stringify(all_Tshirts)),
colorSizeSlug: JSON.parse(JSON.stringify(colorSizeSlug)),
}, // will be passed to the page component as props
};
}
export default Slug;
The key here is to use router push with shallow set as true, in order to avoid page rerendering.
const refreshVariant = (newsize, newcolor) => {
const url = `http://localhost:3000/products/${colorSizeSlug[newcolor][newsize]["slug"]}`
router.push(url, undefined, { shallow: true })
}
Instead of using window.location you need to use router.push
https://nextjs.org/docs/api-reference/next/router#routerpush

how can I update an input and submit it.?

I Want if I click on the edit icon the text will appear in input and I can edit it and when I submit it will edit not created again.
I did the click on edit icon the text will appear in input but when I submit its created as new, so how can I do that?
here is a gif of what I have i want in submit will be updated
app.js
function App() {
const [tasks, setTask]=useState([])
const [title, setTitle]=useState("")
const [changeTasks , setChangeTasks ] = useState(false)
const [edit, setEdit]=useState(false)
useEffect(() => {
axios.get('/tasks')
.then(data=>setTask(data.data))
.catch(err => console.log(err))
}, [changeTasks]);
const addTask = (e) =>{
e.preventDefault()
axios.post('/tasks/create', {title:title, completed: true})
.then(data => setChangeTasks(pre => !pre))
.catch(err => console.log(err))
// to empty input after submit
setTitle("")
if(edit === true){
// do axios.put, but its in other component how could i do that
}
}
return (
<div className="relative flex min-h-screen bg-gray-200 flex-col justify-center overflow-hidden bg-gray-50 py-6 sm:py-12">
<h1 className="flex justify-center p-4 md:p-0 mx-px md:mt-4 md:mb-3 text-center font-extrabold text-transparent text-8xl bg-clip-text bg-gradient-to-r from-purple-800 to-pink-300">
To Do List
</h1>
<div className="relative bg-white px-6 pt-10 pb-8 shadow-xl ring-1 ring-gray-900/5 sm:mx-auto sm:max-w-lg sm:rounded-lg sm:px-10">
<div className="p-2">
<figure className="mb-4">
<blockquote className="italic font-extralight text-slate-700 mb-5">
<q> To-Do lists help us break life into small steps. </q>
<figcaption className="ml-5 text-sm">—Randy Pausch</figcaption>
</blockquote>
</figure>
<form onSubmit={addTask} >
<input
onChange={({target})=>{
setTitle(target.value)
}}
type="text"
className="p-3 mt-2 mb-4 w-full bg-slate-200 rounded border-2 border-slate-200 focus:border-slate-600 focus:outline-none placeholder:italic"
placeholder="Add Your Task..."
value={title}
/>
</form>
<ul>
{tasks.map(ele => <Task {...ele} setChangeTasks = {setChangeTasks} setTitle={setTitle} setEdit={ setEdit}/>)}
</ul>
</div>
</div>
</div>
);
}
export default App;
Task.jsx
import axios from 'axios'
const Task = ({title, id, completed,setChangeTasks, setTitle, setEdit}) => {
const updateTask =()=>{
axios.put(`/tasks/${id}/update`,{title:title,completed : ! completed })
.then(data => setChangeTasks(pre => !pre))
.catch(err => console.log(err))
}
const deleteTask =()=>{
axios.delete(`/tasks/${id}/delete`)
.then(data => setChangeTasks(pre => !pre))
.catch(err => console.log(err))
}
const editTask =()=>{
axios.put(`/tasks/${id}/update`,{title:title})
.then(data => setChangeTasks())
.catch(err => console.log(err))
setEdit(true)
setTitle(title)
}
return (
<li>
<div className="mt-7 ml-3 flex justify-between">
<label className="inline-flex items-center ">
<input
onClick={updateTask}
type="checkbox"
className=" h-6 w-5 accent-violet-200 hover:accent-violet-200 border-0 rounded-md focus:ring-0"
/>
<span className={ completed ? "ml-4 text-lg" : "ml-4 text-lg line-through"} >{title}</span>
</label>
<div className="">
<button onClick={deleteTask} className="mx-4 text-purple-700 hover:text-white hover:bg-purple-600 p-1 px-2 rounded">
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth="2"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</button>
<button onClick={editTask} class=" text-purple-700 hover:text-white hover:bg-purple-600 p-1 px-2 rounded">
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"
/>
</svg>
</button>
</div>
</div>
</li>
)
}
export default Task

React JS update classes when useState is updated

I am trying to make a carousel slider in react. Now am I checking the state and if the state is 2 for example add the tailwind class -left-1/3. Now that is working all fine. But only I have to click twice before it adds the first switch case. Does anyone know if there is a way (maybe with useEffect) to update or reload when the stae is getting updated?
const Hero = () => {
const [sliderIndex, setSliderIndex] = useState(1);
const [sliderClass, setSliderClass] = useState("-left-0");
console.log(sliderIndex);
const nextSlide = () => {
setSliderIndex(sliderIndex + 1);
console.log("onclick", sliderIndex);
switch (sliderIndex) {
case 1:
setSliderClass("-left-0");
break;
case 2:
setSliderClass(`-left-1/${dataSlider.length}`);
break;
case 3:
setSliderClass(`-left-2/${dataSlider.length}`);
break;
}
if (sliderIndex >= dataSlider.length) {
setSliderIndex(1);
}
};
const prevSlide = () => {
console.log("onclick", sliderIndex);
setSliderIndex(sliderIndex - 1);
switch (sliderIndex) {
case 1:
setSliderClass("-left-0");
break;
case 2:
setSliderClass(`-left-1/${dataSlider.length}`);
break;
case 3:
setSliderClass(`-left-2/${dataSlider.length}`);
break;
}
if (sliderIndex < 2) {
setSliderIndex(3);
}
};
useEffect(() => {
console.log("change");
}, [sliderIndex]);
return (
<header className=" w-screen h-[90vh] relative ">
<div className="flex w-[300%] h-full">
{dataSlider.map((obj, index) => {
return (
<>
<div
className={`${sliderClass} transition-all duration-700 relative w-full h-full`}
>
<img
// layout="fill"
// objectFit="cover"
src={`/sliderImg${index + 1}.jpg`}
alt={obj.aboutImg}
className={` object-cover transition-all duration-1000 h-full w-full`}
/>
<div className="absolute left-4 md:left-20 bottom-8">
<h3 className="text-h2 text-primary font-[magilio] leading-none">
{obj.title}
</h3>
<p className="text-white w-[70%] mb-4">{obj.text}</p>
<Link href={obj.btnHref}>
<button className=" px-8 py-4 text-white rounded active:scale-[0.98] hover:scale-[1.02] transition-transform bg-primary ">
{obj.btnText}
</button>
</Link>
</div>
</div>
</>
);
})}
<button
onClick={prevSlide}
className="absolute md:pl-[18px] pl-[9px] rounded md:w-12 md:h-12 w-8 h-8 z-10 active:scale-[0.98] hover:scale-[1.02] transition-transform cursor-pointer top-0 bottom-0 left-0 mt-auto mb-auto ml-4 md:ml-20 bg-white"
>
<svg
width="10"
height="19"
viewBox="0 0 10 19"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect
width="12.368"
height="1.76686"
transform="matrix(0.707425 0.706788 -0.707425 0.706788 1.25 8.18359)"
fill="#111731"
/>
<rect
width="12.368"
height="1.76686"
transform="matrix(-0.707425 0.706788 -0.707425 -0.706788 10 1.92017)"
fill="#111731"
/>
</svg>
</button>
<button
onClick={nextSlide}
className="absolute md:pl-[18px] rotate-180 pl-[9px] rounded md:w-12 md:h-12 w-8 h-8 z-10 active:scale-[0.98] hover:scale-[1.02] transition-transfom cursor-pointer top-0 bottom-0 right-0 mt-auto mb-auto mr-4 md:mr-20 bg-white"
>
<svg
width="10"
height="19"
viewBox="0 0 10 19"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect
width="12.368"
height="1.76686"
transform="matrix(0.707425 0.706788 -0.707425 0.706788 1.25 8.18359)"
fill="#111731"
/>
<rect
width="12.368"
height="1.76686"
transform="matrix(-0.707425 0.706788 -0.707425 -0.706788 10 1.92017)"
fill="#111731"
/>
</svg>
</button>
</div>
</header>
);
};
export default Hero;```
#yainspan is correct in his comment. To explain with a bit of code:
Try to avoid calling setState willy-nilly. I've removed an unnecessary call in this version of prevSlide():
const prevSlide = () => {
console.log("onclick", sliderIndex);
let tempIndex = sliderIndex -1;
if (tempIndex < 2) {
setSliderIndex(3);
}else{
setSliderIndex(tempIndex);
}
};
I've also remove the switch statement as, as yainspan suggests, you can just use sliderIndex to determine what class to add (you'll have to expand on the simplified version here but hopefully the logic is clear):
<div
className={`${sliderIndex === 0 ? '-left-0' : sliderIndex === 1 ? '-left-1' : sliderIndex === 2 ? '-left-2' : '' }transition-all duration-700 relative w-full h-full`}
>

Categories