Reset states of a component when it is closed - reactjs

I have created a MERN application in which on dashboard when a button is clicked a modal box opens which contains some inputs and some options to be selected which are handled using react state hooks. I want when I close modal box the value in it should be reset to default one and when i reopen it all the options should reset to default value
Here is my modal box code
import React, { useState, useContext, useEffect } from "react";
import { UserContext } from "./UserContext";
function SplitModal({
setsplitmodal,
cost,
list,
listobj,
setlistobj,
equal,
setEqual,
payer,
setPayer,
part,
setPart,
setM,
}) {
const [method, setMethod] = useState(true);
const [split, setsplit] = useState(true);
const [owe, setowe] = useState(true);
const [owes, setowes] = useState(true);
const [click, setClick] = useState(false);
const [amount, setAmount] = useState();
const [total, setTotal] = useState(0);
const { user, userfriend } = useContext(UserContext);
console.log(user, "user hu darta koni", user.name);
console.log(listobj);
useEffect(() => {
if (equal === "unequally") {
const _listobj = { ...listobj };
Object.keys(listobj).map((f) => {
_listobj[f] = 0;
});
setlistobj(_listobj);
document.getElementById("InputId").value = "";
console.log(_listobj, "listobjsehu");
}
}, [list, cost]);
const func1 = () => {
setM(false);
setEqual("unequally");
setMethod(false);
const _list = { ...listobj };
_list[list[0]] = -cost;
_list[list[1]] = cost;
setlistobj(_list);
setowe(false);
setowes(true);
setPayer(list[1]);
setPart(`(You owe ${list[1]} ₹${cost})`);
};
const func2 = () => {
setM(false);
setEqual("unequally");
setMethod(false);
const _list = { ...listobj };
const b = _list[list[0]];
_list[list[0]] = +cost;
_list[list[1]] = -cost;
setlistobj(_list);
setPayer(list[0]);
setowe(true);
setowes(false);
setPart(`(${list[1]} owes you ₹${cost})`);
// console.log(owe, owes, click);
};
const distriequal = () => {
setM(true);
// setowe(true);
// setowes(true);
setPart(`(₹${(cost / list.length).toFixed(2)}/person)`);
setMethod(true);
setEqual("equally");
setTotal(0);
const _list = { ...listobj };
list.map((f) => {
if (f === payer) {
_list[f] = (cost - cost / list.length).toFixed(2);
} else {
_list[f] = -(cost / list.length).toFixed(2);
}
setlistobj(_list);
});
};
// console.log(listobj.exp[list[1]], listobj);
const distriamount = (e, i) => {
if (e.key === "Backspace") setM(true);
if (parseInt(e.target.value) > cost) setAmount("err");
else setAmount("");
// console.log( a.replace(a,e.targetvalue));
const _list = { ...listobj };
if (list[i] === payer) {
// _list[list[i]] = e.target.value;
// setOwner(e.target.value);
_list[payer] = parseInt(cost - e.target.value);
} else {
_list[list[i]] = -e.target.value;
}
setlistobj(_list);
if (listobj[user.name] > 0)
setPart(`You get back ₹${Math.abs(_list[user.name])}`);
else if (listobj[user.name] < 0)
setPart(`You owe ₹${Math.abs(_list[user.name])}`);
else setPart(`You owe nothing`);
};
// useEffect(() => {
// Object.keys(listobj).map((f) => {
// if (f === user.name) {
// console.log("nmnm");
// setTotal(total + owner);
// } else setTotal(total + Math.abs(listobj[f]));
// });
// }, [listobj]);
console.log(listobj, list);
return (
<div>
<div className="splitmodal">
<div
style={{
backgroundColor: "#1cc29f",
border: "1px solid #eeeeee",
padding: "5px",
display: "flex",
borderRadius: "10px 10px 0px 0px",
color: "white",
}}
>
<h5 style={{ marginLeft: "100px" }}>Choose Payer</h5>
<button
style={{ position: "absolute", right: "10px" }}
onClick={() => {
setsplitmodal(false);
}}
>
<i class="fas fa-times" />
</button>
</div>
{list.length === 2 ? (
<div className="bg-white splitmodal-main1">
<button
onClick={() => {
setMethod(true);
setM(true);
setClick();
setowe(true);
setowes(true);
}}
>
Split the expense
</button>
<button
onClick={() => {
{
setClick("owe");
return owe ? func1() : null;
}
}}
className={click === "owe" ? "click" : null}
>
You owe {list[1]} ₹{cost}
</button>
<button
className="mb-2"
onClick={() => {
{
setClick("owes");
return owes ? func2() : null;
}
}}
className={click === "owes" ? "click" : null}
>
{list[1]} owes you ₹{cost}
</button>
</div>
) : null}
{method ? (
<div className="splitmodal-main2">
<hr style={{ margin: "10px" }} />
<div className="flex justify-content-center">
<button
style={{
border: "1px solid #ccc",
borderRadius: "5px 0px 0px 5px",
}}
className={equal === "equally" ? "select" : "deselect"}
onClick={() => {
distriequal();
}}
>
Split equally
</button>
<button
style={{
border: "1px solid #ccc",
borderRadius: "0px 5px 5px 0px",
}}
className={equal === "unequally" ? "select" : "deselect"}
onClick={() => {
setEqual("unequally");
}}
>
Split by amounts
</button>
</div>
{equal === "equally" ? (
<div>
<div className="splitmodal-main3">
<h5 className="mt-2 ml-3">Split equally</h5>
<ul
style={{
display: "flex",
flexDirection: "column",
marginLeft: "10px",
}}
>
{list.map((f) => {
return (
<li className="flex align-items-center m-2">
<img
src="https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-grey47-50px.png"
alt=""
/>
<span className="ml-2 font-bold">{f}</span>
<span className="absolute right-10 ">
₹{cost ? (cost / list.length).toFixed(2) : 0.0}
</span>
</li>
);
})}
</ul>
</div>
</div>
) : (
<div>
<div className="splitmodal-main3">
<h5 className="mt-2 ml-3">Split by amounts</h5>
<ul
style={{
display: "flex",
flexDirection: "column",
marginLeft: "10px",
}}
>
{list.map((f, i) => {
return (
<li key={i} className="flex align-items-center m-2">
<img
src="https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-grey47-50px.png"
alt=""
/>
<span className="ml-2 font-bold">{f}</span>
<span className="absolute right-5 ">
<span
style={{
backgroundColor: "#EEEEEE",
paddingLeft: "14px",
paddingRight: "14px",
border: "1px solid #ccc",
borderRadius: "4px 0px 0px 4px",
}}
>
₹
</span>
<input
type="number"
// value={Math.abs(listobj[f])}
id="InputId"
style={{
width: "60px",
border: "1px solid #ccc",
borderRadius: "0px 4px 4px 0px",
height: "23.33px",
}}
className={
amount === "err" ? "text-red-500" : null
}
onChange={(e) => {
distriamount(e, i);
}}
/>
</span>
</li>
);
})}
</ul>
</div>
{/* <div className="mt-2 ml-3">
<h5>Total:</h5>
<span className="absolute right-10 bottom-0 ">₹{total}</span>
</div> */}
</div>
)}
</div>
) : null}
</div>
</div>
);
}
export default SplitModal;
Please help me solving this

As a workaround you can write a new useEffect() that reset all the value at the loading of your component, something like :
useEffect(() => {
setMethod(true);
setsplit(true);
setowe(true);
setowes(true);
setClick(false);
setAmount();
setTotal(0);
}, []);

We don't actually need a separate effect to perform the cleanup. useEffect is designed to keep it together.
Learn more on: https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup
useEffect(() => {
// your other codes
return function reset() {
setMethod(true);
setsplit(true);
setowe(true);
setowes(true);
setClick(false);
setAmount(0);
setTotal(0);
}
}, []);

Related

The react-use-cart needs the string ( id ) but my api data only generates the object ( _id ), how can I change it and use it normally?

I'm creating a cart and I need to add the item, the function has the id of the item as a requirement, but my item only generates the _id and not just the id. The problem to be simple for those who have a lot of knowledge, thanks in advance to the collaborators
https://www.npmjs.com/package/react-use-cart
Index.js ( Product details )
import React, { useState, useEffect } from "react";
import { useParams } from "react-router";
import Popup from "reactjs-popup";
import "reactjs-popup/dist/index.css";
import { ThreeDots } from "react-loader-spinner";
import { useCart } from "react-use-cart";
//Local
import Nav from "../../components/Nav";
import api from "../../../services/api";
import Best from "../Best/index";
import { TitleCaurosel } from "../style";
//Icons / Images
import { AiFillStar } from "react-icons/ai";
import { BsArrowLeft, BsArrowRight } from "react-icons/bs";
//Style
import {
Product,
Images,
Main,
Other,
Details,
Title,
Description,
Stars,
Colors,
Color,
ColorSelected,
Price,
Cart,
} from "./style";
const Index = () => {
const params = useParams();
const { addItem } = useCart();
const [data, setData] = useState(undefined);
const [error, setError] = useState(undefined);
const [color, setColor] = useState(undefined);
const [nameColor, setNameColor] = useState(undefined);
const [index, setIndex] = useState(0);
const [popup, setPopup] = useState(false);
const [current, setCurrent] = useState(0);
const [main, setMain] = useState(undefined);
const ref = React.createRef();
const { height, width } = useWindowDimensions();
function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height,
};
}
function useWindowDimensions() {
const [windowDimensions, setWindowDimensions] = useState(
getWindowDimensions()
);
useEffect(() => {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return windowDimensions;
}
const config = {
headers: {
"Content-type": "application/json",
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
};
useEffect(() => {
api.get(`/items/${params.id}`).then((response) => setData(response.data));
}, []);
const addToCart = () => {
if (color !== undefined) {
api
.post(
`/cart`,
{
itemId: params.id,
quantity: 1,
colors: data.images,
colorSelected: color,
img: data.images[0].src,
},
config
)
.then((response) => {
if (response.status === 200 || response.status === 201) {
window.location.pathname = "/Cart";
}
});
} else {
setError(1);
}
};
const numberFormat = (value) =>
new Intl.NumberFormat("pt-br", {
style: "currency",
currency: "BRL",
}).format(value);
const handleTab = (index) => {
setMain(undefined);
setIndex(index);
if (color !== undefined && nameColor !== undefined) {
setColor(undefined);
setNameColor(undefined);
}
};
const nextSlide = () => {
setCurrent(current === data.images.length - 1 ? 0 : current + 1);
};
const prevSlide = () => {
setCurrent(current === 0 ? data.images.length - 1 : current - 1);
};
useEffect(() => {
if (data !== undefined) {
if (!Array.isArray(data.images) || data.images.length <= 0) {
return null;
}
}
});
const changeColor = (id, name) => {
setColor(id);
setNameColor(name);
setError(undefined);
const filter = data.images.filter((item) => item._id === id);
setMain(filter[0].src);
};
return data !== undefined ? (
<div>
{/*Popup*/}
{popup === true && (
<Popup
open={true}
position="center center"
onClose={() => setPopup(false)}
>
<section className="slider">
<BsArrowLeft className="left-arrow" onClick={prevSlide} />
<BsArrowRight className="right-arrow" onClick={nextSlide} />
{data.images.map((slide, index) => {
return (
<div
className={index === current ? "slide active" : "slide"}
key={index}
>
{index === current && (
<div
style={{
width: width / 2,
height: height / 2,
backgroundImage: `url(${slide.src})`,
backgroundRepeat: "no-repeat",
backgroundSize: "contain",
backgroundPosition: "center",
}}
/>
)}
</div>
);
})}
</section>
</Popup>
)}
<Nav />
<div
style={{
height: "90vh",
display: "grid",
justifyContent: "center",
alignItems: "center",
gridTemplateColumns: "85%",
gridTemplateRows: "100%",
gridColumnGap: "5px",
}}
>
<Product key={data._id}>
<Images>
<div
style={{
display: "grid",
marginRight: "3%",
height: height / 1.3,
}}
ref={ref}
>
<Other
style={{
width: width / 10,
backgroundImage: `url(${data.images[0].src})`,
backgroundPosition: "center",
backgroundRepeat: "no-repeat",
backgroundSize: "60%",
}}
alt={`Image de ${data.name}`}
key={0}
onClick={() => handleTab(0)}
/>
{data.images[1] !== undefined && (
<Other
style={{
marginTop: "5%",
width: width / 10,
backgroundImage: `url(${data.images[1].src})`,
backgroundPosition: "center",
backgroundRepeat: "no-repeat",
backgroundSize: "60%",
}}
alt={`Image de ${data.images[1].name}`}
key={1}
onClick={() => handleTab(1)}
/>
)}
{data.images[2] !== undefined && (
<Other
style={{
marginTop: "5%",
width: width / 10,
backgroundImage: `url(${data.images[2].src})`,
backgroundPosition: "center",
backgroundRepeat: "no-repeat",
backgroundSize: "60%",
}}
alt={`Image de ${data.name}`}
key={2}
onClick={() => handleTab(2)}
/>
)}
{data.images[3] !== undefined && (
<Other
style={{
marginTop: "5%",
width: width / 10,
backgroundImage: `url(${data.images[3].src})`,
backgroundPosition: "center",
backgroundRepeat: "no-repeat",
backgroundSize: "60%",
}}
alt={`Image de ${data.name}`}
key={1}
onClick={() => handleTab(3)}
/>
)}
{data.images[4] !== undefined && (
<div>
{data.images.length < 5 ? (
<Other
style={{
width: width / 10,
backgroundImage: `url(${data.images[3].src})`,
backgroundPosition: "center",
backgroundRepeat: "no-repeat",
backgroundSize: "60%",
}}
alt={`Image de ${data.name}`}
key={2}
onClick={() => handleTab(3)}
/>
) : (
<Other
style={{
width: width / 10,
}}
onClick={() => setPopup(true)}
alt={`Image de ${data.name}`}
>
<p>+ 5</p>
</Other>
)}
</div>
)}
</div>
<div
style={{
backgroundColor: "#F6F6F6",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<Main
style={{
backgroundImage: `url(${
main === undefined ? data.images[index].src : main
})`,
backgroundPosition: "center",
backgroundRepeat: "no-repeat",
backgroundSize: "80%",
width: width / 2.8,
height: height / 1.5,
}}
/>
</div>
</Images>
<Details>
<Title>{data.name}</Title>
<Description>{data.description}</Description>
<Stars>
<AiFillStar />
<AiFillStar />
<AiFillStar />
<AiFillStar />
<AiFillStar />
<p>441 Avaliações</p>
</Stars>
<Colors>
{error === undefined && color === undefined && (
<p style={{ color: "#000" }}>Selecione uma cor:</p>
)}
{error === 1 && color === undefined && (
<p style={{ color: "#ff0000" }}>
Selecione uma cor: (Obrigatório)
</p>
)}
{error === undefined &&
color !== undefined &&
nameColor !== undefined && (
<p style={{ color: "#000" }}>Cor selecionada: {nameColor}</p>
)}
<div
style={{
display: "flex",
marginTop: "1%",
width: "100%",
flexWrap: "wrap",
alignItems: "center",
}}
>
{data.images.map((item) =>
color === item._id ? (
<ColorSelected onClick={() => setColor(undefined)}>
<div style={{ backgroundColor: item.color }} />
</ColorSelected>
) : (
<Color
style={{ backgroundColor: item.color }}
onClick={() => {
changeColor(item._id, item.name);
}}
/>
)
)}
</div>
</Colors>
<Price>{numberFormat(data.price)}</Price>
{console.log(data)}
<Cart onClick={() => addItem(data)}>
Adicionar ao carrinho
</Cart>
</Details>
</Product>
</div>
<div style={{ paddingLeft: "130px" }}>
<TitleCaurosel>Você pode gostar!</TitleCaurosel>
<Best />
</div>
</div>
) : (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
width: width,
height: height,
}}
>
<ThreeDots
height="300"
width="300"
radius="9"
color="#8c6d55"
ariaLabel="three-dots-loading"
wrapperStyle={{}}
wrapperClassName=""
visible={true}
/>
</div>
);
};
export default Index;
Cart.js
import React, { useState, useEffect } from "react";
import Nav from "../components/Nav";
import Select from "react-select";
import api from "../../services/api";
import { ThreeDots } from "react-loader-spinner";
import { useCart } from "react-use-cart";
//Icons
import { BiTrash } from "react-icons/bi";
import { MdOutlineEditLocationAlt } from "react-icons/md";
import { HiOutlineShoppingBag } from "react-icons/hi";
//Style
import {
Container,
Box1,
Box2,
Box3,
Title,
Product,
Image,
Name,
Price,
Border,
Stock,
PriceTotal,
Delete,
Cupom,
BorderTraced,
Subtotal,
Items,
Total,
Checkout,
NextToBuy,
Empty,
} from "./style";
const Index = () => {
function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height,
};
}
function useWindowDimensions() {
const [windowDimensions, setWindowDimensions] = useState(
getWindowDimensions()
);
useEffect(() => {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return windowDimensions;
}
const { height, width } = useWindowDimensions();
const {
isEmpty,
items,
cartTotal,
updateItemQuantity,
removeItem,
emptyCart,
} = useCart();
return (
<Container>
{isEmpty ? (
<Empty>
<Nav />
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
textAlign: "center",
height: "80vh",
}}
>
<div>
<HiOutlineShoppingBag className="icon-empty" />
<h1>Sua sacola está vazia</h1>
<p className="text-empty">
Parece que você não adicionou nada a sua sacola. <br /> Vá em
frente e explore as principais categorias.
</p>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
textAlign: "center",
}}
>
<a className="button" href="/#Produtos">
Explorar produtos
</a>
</div>
</div>
</div>
</Empty>
) : (
<Container>
<Nav />
<div
style={{
display: "flex",
justifyContent: "center",
height: height,
marginTop: "3%",
marginBottom: "10%",
}}
>
<Box1 style={{ width: width / 2.8, height: height }}>
<Title>Seus items</Title>
</Box1>
<div>
<Box2 style={{ width: width / 4, height: height / 5 }}>
<Title>Frete</Title>
<p className="title">Endereço:</p>
<span></span>
<span></span>
<p className="title">Estimativa de entrega:</p>
<span>30/12/2022</span>
<MdOutlineEditLocationAlt />
</Box2>
<Box3 style={{ width: width / 4, height: height / 1.4 }}>
<Cupom>
<input placeholder="Cupom de desconto" />
<button>Aplicar</button>
</Cupom>
<BorderTraced />
<Subtotal>
<p>Subtotal</p>
<p></p>
</Subtotal>
<Items>
<div>
<p>Frete</p>
<p>R$ 399,99</p>
</div>
</Items>
<BorderTraced />
<Total>
<p>Total</p>
<p></p>
</Total>
<Checkout>Finalizar compra</Checkout>
<NextToBuy
onClick={() => {
window.location.pathname = "/Products";
}}
>
Continuar comprando
</NextToBuy>
</Box3>
</div>
</div>
</Container>
)}
</Container>
);
};
export default Index;
Index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import Routes from './routes';
import { CartProvider } from 'react-use-cart';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<CartProvider>
<Routes />
</CartProvider>
</React.StrictMode>
);
Not sure if this is the best/most efficient approach, but you could always create an Item object with the attributes required for the addItem() method. Then map the required data from your data object to the new item object, and instead of using addItem(data) you could use addItem(item).
Add the property when setting the value:
useEffect(() => {
api.get(`/items/${params.id}`)
.then(({ data }) => {
setData({
...data,
id: data._id
});
});
}, []);

Setting content editable returns Cannot create property 'contentEditable' on string error

I am visualising a List of Cards with content and what I want to achieve is to set contentEditable=true to the clicked card via its button. I am able to select the content of the element, however contentEditable is not set to true and it returns the following error instead:
Uncaught TypeError: Cannot create property 'contentEditable' on string
And I cant figure out why. What am I doing wrong here and how can I set contentEditable to true for the clicked element via its button?
Here is my code:
import * as React from 'react';
import { ListView } from '#progress/kendo-react-listview';
import { Input } from '#progress/kendo-react-inputs';
import {
Card,
CardTitle,
CardImage,
CardActions,
CardBody,
} from '#progress/kendo-react-layout';
import { Pager } from '#progress/kendo-react-data-tools';
import articles from '../data/articles.json';
import { BubbleChart } from "../components/products/BubbleChart"
const onEdit = (item) => {
console.log(item.Content)
let cardContent = item.Content.contentEditable = "true";
return cardContent
}
const MyItemRender = (props) => {
let item = props.dataItem;
return (
<div
style={{
padding: '20px 20px',
}}
className="parent-container"
>
<div className="k-card-list">
<Card
style={{
width: 260,
height: 340
}}
>
<CardBody
style={{
borderBottom: 'solid 1px rgba(0,0,0,.08)'
}}
>
<CardImage
src={require(`../assets/article-images/${item.Image}`)}
style={{
width: 260,
height: 140,
maxWidth: 260,
}}
/>
<CardTitle
style={{
fontSize: 18,
}}
/>
<CardTitle>{item.Title}</CardTitle>
<CardTitle>{item.Subtitle}</CardTitle>
<p className="content">
Some quick example text to build on the card title and make up the
bulk of the card content.
</p>
</CardBody>
<CardActions>
<div className="footer-buttons-container">
<span>
<span className="k-button k-button-md k-button-rectangle k-rounded-md k-button-flat k-button-flat-base">
<span className="k-icon k-i-preview"></span>Review
</span>
</span>
<span>
<span className="k-button k-edit-button k-button-md k-button-rectangle k-rounded-md k-button-flat k-button-flat-primary" onClick={() => onEdit(item)}>
<span className="k-icon k-i-edit"></span>Edit
</span>
</span>
</div>
</CardActions>
</Card>
</div>
</div>
);
};
export const Products = () => {
const [filteredList, setFilteredList] = React.useState(articles);
const [value, setValue] = React.useState('');
const [page, setPage] = React.useState({
skip: 0,
take: 10,
});
const handlePageChange = (e) => {
setPage({
skip: e.skip,
take: e.take,
});
};
const handleChange = React.useCallback((event) => {
setValue(event.target.value);
const results = articles.filter(post => {
if (event.target.value === "") return articles
return post.Title.includes(event.target.value)
})
console.log(results)
setFilteredList(results)
});
const { skip, take } = page;
return <div>
<div className="chart-container">
<br/>
<br/>
<BubbleChart/>
</div>
<div className="input-container">
<Input
style={{
border: '2px solid #ccc',
boxShadow: 'inset 0px 0px 0.5px 0px rgba(0,0,0,0.0.1)',
}}
placeholder={'Search'}
value={value}
onChange={handleChange}
/>
</div>
<div className="listbox-card-container">
<ListView
data={filteredList.slice(skip, skip + take)}
item={MyItemRender}
style={{
width: '100%',
height: '100%',
}}
/>
<Pager
skip={skip}
take={take}
onPageChange={handlePageChange}
total={articles.length}
/>
</div>
</div>
}
Can't do multiple assigning in one line. add separate lines
const onEdit = (item) => {
console.log(item.Content)
const content = {...item.Content }
content.contentEditable = "true";
return content
}

Unable to update react range values through input

I'm writing a code where I'm using react-range to create a range bar. along with it, I've got 2 textboxes that have the min and max values of the range. Currently, I'm able to update the range values by dragging and the text boxes get updated automatically. And I also want to update the price range using the textboxes mentioned, currently, the min box value works fine, but, when I try to update the max value, the value gets appended instead of updating. Unable to know where I'm going wrong.
Here is the code of the same.
import { useState } from "react";
import { Range, getTrackBackground } from "react-range";
export const PriceRange = () => {
const [priceValues, setPriceValues] = useState([1, 100]);
let step = 1;
const handleChange = (values: number[]) => {
if (values[0] > values[1]) {
values[0] = values[1];
}
if (values[1] < values[0]) {
values[1] = values[0];
}
setPriceValues(values);
};
return (
<>
{
<div
style={{
width: "50%",
maxWidth: "50%",
marginLeft: "auto",
marginRight: "auto"
}}
>
<div className="mb-8 text-gray-900 text-sm font-medium text-left">
Price
</div>
<div
style={{ padding: "1rem", marginTop: "1rem", marginBottom: "1rem" }}
>
<Range
step={step}
min={priceValues[0]}
max={priceValues[1]}
values={priceValues}
onChange={(values) => handleChange(values)}
renderTrack={({ props, children }) => (
<div
{...props}
style={{
...props.style,
background: getTrackBackground({
values: priceValues,
colors: ["#c4c4c442", "black", "#c4c4c442"],
min: priceValues[0],
max: priceValues[1]
}),
height: "0.5rem",
width: "100%"
}}
>
{children}
</div>
)}
renderThumb={({ index, props }) => (
<div
{...props}
style={{
...props.style
}}
className="thumbs"
>
<div className="priceValues">{`$${
priceValues[index] === priceValues.length - 1
? priceValues[index] + "+"
: priceValues[index]
}`}</div>
</div>
)}
/>
</div>
<div className="rangeBoxesContainer">
<div className="rangeBox">
<div style={{ display: "flex" }}>Min $</div>
<input
className="rangeInputbox"
type="number"
value={priceValues[0]}
onChange={(e) => {
if (Number(e.target.value) < Number(priceValues[1])) {
let newValue = [...priceValues];
newValue[0] = Number(e.target.value);
setPriceValues(newValue);
}
}}
/>
</div>
<div className="rangeBox">
<div style={{ display: "flex" }}>Max $</div>
<input
className="rangeInputbox"
type="number"
value={priceValues[1]}
onChange={(e) => {
if (Number(e.target.value) > Number(priceValues[1])) {
let newValue = [...priceValues];
newValue[1] = Number(e.target.value);
setPriceValues(newValue);
}
}}
/>
</div>
</div>
</div>
}
</>
);
};
And here is a working code sandbox link. Can someone let me know where I'm going wrong?
Thanks

Sync scroll react. div block with main scroll on window

I want to synchronize a divs scroll with a body scroll.
I tried some examples with two divs but I couldn't manage fix it with the body scroll.
Sample code with two divs: https://codesandbox.io/s/react-custom-scroll-sync-of-2-divs-10xpi
My Code
https://codesandbox.io/s/funny-rain-ditbv
import "./styles.css";
import { useRef } from "react";
export default function App() {
const firstDivRef = useRef();
const secondDivRef = useRef();
const handleScrollFirst = (scroll) => {
secondDivRef.current.scrollTop = scroll.target.scrollTop;
};
const handleScrollSecond = (scroll) => {
firstDivRef.current.scrollTop = scroll.target.scrollTop;
};
return (
<div
className="App"
style={{
display: "flex",
}}
>
<div
onScroll={handleScrollFirst}
ref={firstDivRef}
style={{
height: "500px",
overflow: "scroll",
backgroundColor: "#FFDAB9",
position: "sticky",
top: "0px"
}}
>
<div style={{ height: 5000, width: 300 }}>
The first div (or it can be tbody of a table and etc.)
{[...new Array(1000)].map((_, index) => {
const isEven = index % 2 === 0;
return (
<div style={{ backgroundColor: isEven ? "#FFFFE0 " : "#FFDAB9" }}>
{index}
</div>
);
})}
</div>
</div>
<div
onScroll={handleScrollSecond}
ref={secondDivRef}
style={{
height: "100%",
backgroundColor: "#EEE8AA"
}}
>
<div style={{ height: 5000, width: 200 }}>
The second div
{[...new Array(1000)].map((_, index) => {
const isEven = index % 2 === 0;
return (
<div style={{ backgroundColor: isEven ? "#FFFFE0 " : "#FFDAB9" }}>
{index}
</div>
);
})}
</div>
</div>
</div>
);
}
It was easy to use different divs rather than using a div and window.
But finally managed to run it with a div and the body.
The trick is they block each other since they listen each others values.
import "./styles.css";
import { useEffect, useRef, useState } from "react";
export default function App() {
const firstDivRef = useRef();
const [scrollTop, setScrollTop] = useState(0);
const [disableBodyScroll, setDisableBodyScroll] = useState(false);
const handleScrollFirst = (scroll) => {
setScrollTop(scroll.target.scrollTop);
};
useEffect(() => {
if (firstDivRef.current && !disableBodyScroll) {
firstDivRef.current.scrollTop = scrollTop;
}
if (disableBodyScroll) {
window.scrollTo(0, scrollTop);
}
}, [firstDivRef, scrollTop, disableBodyScroll]);
useEffect(() => {
const onScroll = () => {
console.log(disableBodyScroll, window.scrollY);
if (!disableBodyScroll) {
setScrollTop(window.scrollY);
}
};
// clean up code
window.removeEventListener("scroll", onScroll);
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, [disableBodyScroll]);
return (
<div
className="App"
style={{
display: "flex"
}}
>
<div
onMouseEnter={() => setDisableBodyScroll(true)}
onMouseLeave={() => setDisableBodyScroll(false)}
onScroll={handleScrollFirst}
ref={firstDivRef}
style={{
height: "500px",
overflow: "scroll",
backgroundColor: "#FFDAB9",
position: "sticky",
top: "0px"
}}
>
<div style={{ height: 5000, width: 300 }}>
The first div (or it can be tbody of a table and etc.)
{[...new Array(1000)].map((_, index) => {
const isEven = index % 2 === 0;
return (
<div style={{ backgroundColor: isEven ? "#FFFFE0 " : "#FFDAB9" }}>
{index}
</div>
);
})}
</div>
</div>
<div
style={{
height: "100%",
backgroundColor: "#EEE8AA"
}}
>
<div style={{ height: 5000, width: 200 }}>
The second div
{[...new Array(1000)].map((_, index) => {
const isEven = index % 2 === 0;
return (
<div style={{ backgroundColor: isEven ? "#FFFFE0 " : "#FFDAB9" }}>
{index}
</div>
);
})}
</div>
</div>
</div>
);
}
https://codesandbox.io/s/ancient-dream-tzuel?file=/src/App.js
Try the next example. This is a quick sketch but maybe it will help you.
https://codesandbox.io/s/gallant-goldwasser-19g4d?file=/src/App.js

Why the value of clientHeight of <li> element does not change when scrolling?

I am trying to hide the <li></li> element when it's overflowing (while scrolling, and just before scrolling after adding some products to the shopping cart), however, the clientHeight on the overflowingRef, which refers to the <li></li> element does not change when its content is overflowing. Any idea what i m doing wrong?
Please see the code for reference below:
import React, {useState, useRef, useEffect} from 'react';
import products from './mock.json';
export default function App() {
return (
<div style={{display: 'flex', flexDirection: 'row'}}>
<ShoppingCart products={products} />
</div>
);
}
function List({products, title, addProduct, removeProduct}) {
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'start-end',
}}
>
{title}
<ul
style={{
listStyle: 'none',
paddingInlineStart: '0px',
width: '500px',
height: '260px',
overflow: 'scroll',
paddingRight: '10px',
}}
>
{products.length === 0 ? (
<div>No products</div>
) : (
products.map(({category, price, stocked, name}, index) => (
<SuspendDisplayIfOverflowing>
{ref => (
<li
style={{
padding: '10px',
border: '1px solid blue',
display: 'flex',
justifyContent: 'space-between',
height: '18px',
overflow: 'scroll',
}}
ref={ref}
key={price}
>
<div style={{color: `${stocked ? 'green' : 'red'}`}}>
{`${name} - ${category} - available: ${stocked} - price: ${price}`}
</div>
{addProduct && stocked ? (
<button
onClick={() =>
addProduct({category, price, stocked, name})
}
>
Add
</button>
) : null}
{removeProduct ? (
<button onClick={() => removeProduct(index)}>Remove</button>
) : null}
</li>
)}
</SuspendDisplayIfOverflowing>
))
)}
</ul>
<Total prices={products.map(({price}) => getCleanPrice(price))} />
</div>
);
}
function ShoppingCart({products}) {
const [productsInCart, manipulateProduct] = useState([]);
const addProduct = product =>
manipulateProduct(productsInCart.concat(product));
const removeProduct = productIndex =>
manipulateProduct(
productsInCart.filter((_, index) => index !== productIndex),
);
return (
<>
<List
title="Available Products"
products={products}
addProduct={addProduct}
/>
<List
title="Shopping Cart"
products={productsInCart}
removeProduct={removeProduct}
/>
</>
);
}
function Total({prices}) {
const total = prices.reduce((accum, item) => (accum += parseFloat(item)), 0);
return <div>Total amount to pay: {total.toFixed(2)}</div>;
}
function getCleanPrice(price) {
return price.slice(1);
}
function SuspendDisplayIfOverflowing(props) {
const overflowingRef = useRef(null);
useEffect(() => {
console.log(
'oveflowing scroll height',
overflowingRef.current.scrollHeight,
);
console.log(
'oveflowing client height',
overflowingRef.current.clientHeight,
);
console.log(
'oveflowing client height',
overflowingRef.current.offsetHeight,
);
console.log(overflowingRef.current);
}, [overflowingRef]);
return props.children(overflowingRef);
}

Resources