Unable to type in an input field when adding item to cart in React

The logic I'm try to apply here may be totally wrong. This is the first time I'm attempting to do something like this (trying to use an input field to get value of the number of items to be added to cart). I'm not able to type in the input field.

    const [qty, setQty] = useState(1)
    const submitHandler = (e) => {
        e.preventDefault()
        if(e.target.value <=product.countInStock && e.target.value > 0){
                setQty(e.target.value)
                history.push(`/cart/${match.params.id}?qty=${qty}`)
        }else{
            alert("Insifficient Quantity in Stock")
            }
    }
========================================
<Row>
    <Col sm={4}>Qty</Col>
    <Col sm={8}>
    <Form onSubmit={submitHandler}>
        <Form.Control
            type="number"
            min="0"
            max={product.countInStock} 
            value={qty}
            onchange={checkInput}                                                         
            />
        <Button
               onClick={addToCartHandler}
                size="lg"
                disabled={product.countInStock === 0}
                type='button'>
                Add to Cart
             </Button>

         </Form>
    </Col>
</Row>

How do I fix it? It seems to be a popular issue that people have asked question on online but still can't find solution to mine


Solution 1:

It seems that you have a problem with your event handlers. Since you pass the value={qty} to the input field, you create a controlled component. However upon updating the input you don't update the parent's state, so in the end the input's value doesn't change.

Try something like this on your input:

<Form.Control
    type="number"
    min={0}
    max={product.countInStock}
    value={qty}
    onchange={(e) => setQty(e)}/> 

(I assume the onChange returns the new value as number. If it doesn't, you'll need to transform the returned data accordingly before checking it in the submit event handler.)

Also update the submitHandler to be:

const submitHandler = (e) => {
    e.preventDefault()
    if (qty <= product.countInStock && qty > 0) {
        history.push(`/cart/${match.params.id}?qty=${qty}`)
    } else {
        alert('Insufficient Quantity in Stock')
    }
}

Solution 2:

Daniel's answer is correct in that a controlled input field won't change its value unless you change the state variable that controls it. So really what you need is to put setQty(e.target.value) inside your checkInput function. That should do the trick.

You could also use useRef to control your form. That way there won't be a need to rerender your elements every time there is a change in the input field. Let me know if you're interested to see how that would look in your case.