I'm trying to use a custom react hook to create a counter for each item in a list. the problem is when I increase or decrease a counter, the value of other counters change simultaneously. basically all of the counters show the same value. here is my custom hook:
import { useState } from "react";
export const useQuantity = (defaultQuantity) => {
const [value, setValue] = useState(defaultQuantity || 1);
const onChange = (e) => {
if (!+e.target.value >= 1) {
setValue(1);
return;
}
setValue(+e.target.value);
};
return {
value,
setValue,
onChange,
};
};
how can I change the value of a counter while it doesn't effect the other counters?
This is the component that I map through the items and for each one of them I render the QuantityInput component.
import { useQuantity } from "../Hook/useQuantity";
import { QuantityInput } from "./QuantityInput";
export const Order = () => {
const quantity = useQuantity();
return (
orders.map((order) => (
<QuantityInput quantity={quantity} />
)
)
}
and this is QuantityInput component:
export const QuantityInput = ({ quantity }) => {
const decrement = () => {
quantity.setValue(quantity.value - 1);
};
const increment = () => {
quantity.setValue(quantity.value + 1);
};
return (
<Button
onClick={decrement}
disabled={quantity.value === 1}
>
-
</Button>
<Input {...quantity} />
<Button onClick={increment}> + </Button>
);
};
Instead of useQuantity
in your parent component, you should use it in QuantityInput
component so each of them hold their state.
export const QuantityInput = () => {
const quantity = useQuantity(); // Use quantity here, do not need to pass from props
const decrement = () => {
quantity.setValue(quantity.value - 1);
};
const increment = () => {
quantity.setValue(quantity.value + 1);
};
return (
<Button
onClick={decrement}
disabled={quantity.value === 1}
>
-
</Button>
<Input {...quantity} />
<Button onClick={increment}> + </Button>
);
};
The hook that you implemented holds one state value and will only suffice for it.
The solution here is to implement a component that uses this hook. Once you have the component you can render as many instances of it as you want
Also you could simply implement a component instead of custom hook
import { useState } from "react";
export const QuantityInput = (props) => {
const [value, setValue] = useState(props.defaultQuantity || 1);
const onChange = (e) => {
if (!+e.target.value >= 1) {
setValue(1);
return;
}
setValue(+e.target.value);
};
return (
<div>
<div>{value}</div>
<input value={value} onChange={onChange} />
</div>
)
};
const Parent = ({arr}) => {
return arr.map(item => <QuantityInput defaultQuantity={item.defaultQuantity} />)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With