I am making a simple app that user can increment or decrement number of adult, child and baby.
I want to manage these state inside one state as a form of object like this below.
const [numberState, setNumberState] = useState({
adultCount: 0,
childCount: 0,
babyCount: 0
});
And below code is the part where user can increase or decrease number of adult, child and baby.
<div className="tit">Number</div>
<dl>
<dt><span>Adult</span></dt>
<dd>
<div className="number_count">
<button type="button" className="btn_minus" onClick={() => handleNumberState("adult", "minus")}>minus</button>
<span className="input-num"><input type="number" value={adultCount} /></span>
<button type="button" className="btn_plus" onClick={() => handleNumberState("adult", "plus")}>plus</button>
</div>
</dd>
<dt><span>Child</span></dt>
<dd>
<div className="number_count">
<button type="button" className="btn_minus" onClick={() => handleNumberState("child", "minus")}>minus</button>
<span className="input-num"><input type="number" value={childCount} /></span>
<button type="button" className="btn_plus" onClick={() => handleNumberState("child", "plus")}>plus</button>
</div>
</dd>
<dt><span>Baby</span></dt>
<dd>
<div className="number_count">
<button type="button" className="btn_minus" onClick={() => handleNumberState("baby", "minus")}>minus</button>
<span className="input-num"><input type="number" value={babyCount} /></span>
<button type="button" className="btn_plus" onClick={() => handleNumberState("baby", "plus")}>plus</button>
</div>
</dd>
</dl>
</div>
As you can see when user clicks the button, it passes two arguments to handleNumberState callback function.
Then function looks like this below.
const handleNumberState = useCallback((gen, state) => {
if (gen === "adult" && state === "minus" && numberState.adultCount > 0) {
setNumberState(prevState => {
return {
adultCount: prevState.adultCount - 1,
childCount: prevState.childCount,
babyCount: prevState.babyCount
}
})
}
if (gen === "adult" && state === "plus") {
setNumberState(prevState => {
return {
adultCount: prevState.adultCount + 1,
childCount: prevState.childCount,
babyCount: prevState.babyCount
}
})
}
if (gen === "child" && state === "minus" && numberState.childCount > 0) {
setNumberState(prevState => {
return {
adultCount: prevState.adultCount,
childCount: prevState.childCount - 1,
babyCount: prevState.babyCount
}
})
}
if (gen === "child" && state === "plus") {
setNumberState(prevState => {
return {
adultCount: prevState.adultCount,
childCount: prevState.childCount + 1,
babyCount: prevState.babyCount
}
})
}
if (gen === "baby" && state === "minus" && numberState.babyCount > 0) {
setNumberState(prevState => {
return {
adultCount: prevState.adultCount,
childCount: prevState.childCount,
babyCount: prevState.babyCount - 1
}
})
}
if (gen === "baby" && state === "plus") {
setNumberState(prevState => {
return {
adultCount: prevState.adultCount,
childCount: prevState.childCount,
babyCount: prevState.babyCount + 1
}
})
}
})
Depends on what arguments get passed to the function, state is changed inside if statement.
But the code seems messy.
Is there a better way I can make this work using less if statement?
Update handler to take a field and value instead.
const handleNumberState = (field, value) => {
setNumberState(prevState => ({
...prevState,
[field]: Math.max(0, prevState[field] + value),
}))
}
Pass the field name and value to add to the handler.
<div className="tit">Number</div>
<dl>
<dt>
<span>Adult</span>
</dt>
<dd>
<div className="number_count">
<button
type="button"
className="btn_minus"
onClick={() => handleNumberState("adultCount", -1)}
>
minus
</button>
<span className="input-num">
<input type="number" value={adultCount} />
</span>
<button
type="button"
className="btn_plus"
onClick={() => handleNumberState("adultCount", 1)}
>
plus
</button>
</div>
</dd>
<dt>
<span>Child</span>
</dt>
<dd>
<div className="number_count">
<button
type="button"
className="btn_minus"
onClick={() => handleNumberState("childCount", -1)}
>
minus
</button>
<span className="input-num">
<input type="number" value={childCount} />
</span>
<button
type="button"
className="btn_plus"
onClick={() => handleNumberState("childCount", 1)}
>
plus
</button>
</div>
</dd>
<dt>
<span>Baby</span>
</dt>
<dd>
<div className="number_count">
<button
type="button"
className="btn_minus"
onClick={() => handleNumberState("babyCount", -1)}
>
minus
</button>
<span className="input-num">
<input type="number" value={babyCount} />
</span>
<button
type="button"
className="btn_plus"
onClick={() => handleNumberState("babyCount", 1)}
>
plus
</button>
</div>
</dd>
</dl>
A minor optimization would be to create a curried handler that consumes a value and returns a callback function consuming the click event
const handleNumberState = value => e => {
e.preventDefault();
const { name } = e.target;
setNumberState((prevState) => ({
...prevState,
[name]: Math.max(0, prevState[name] + value)
}));
};
Give each button a name
attribute which is passed with the click event, ex
<button
name="adultCount"
type="button"
className="btn_minus"
onClick={handleNumberState(-1)}
>
minus
</button>
<span className="input-num">
<input type="number" value={adultCount} />
</span>
<button
name="adultCount"
type="button"
className="btn_plus"
onClick={handleNumberState(1)}
>
plus
</button>
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