Home > other >  It throws me a warning when occupying a form in react on the web
It throws me a warning when occupying a form in react on the web

Time:07-29

I tell you it is a form that the user fills out but when filling out I get the following warning:

"react_devtools_backend.js:4026 Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component."

I would like to know how to solve it and leave it fine, and why this warning comes out, can you explain to me why it happens, if all the elements have the same name in label and input . Thanks I share the code

import React, { useContext, useState } from "react";
import { db } from "../firebase/firebase";
import{ addDoc, doc, collection, serverTimestamp, getDoc, updateDoc } from "firebase/firestore"
import { contextoProducto } from "./ProductContext";
import swal from 'sweetalert';
import { useNavigate } from "react-router-dom";

const CartFinish = () => {

  const Navigate = useNavigate();
  const{ cartProduct, totalPrecio, clearCart } = useContext(contextoProducto);

  const [form, setForm] = useState({});

  
  const finalizarCompra = () => {
    const ventasCollection = collection(db, 'ventas');
    addDoc(ventasCollection, {
      form,
      items: cartProduct,
      date: serverTimestamp(),
      Total: totalPrecio,
      IVA: totalPrecio * 0.19, //IVa en Chile es del 19%
      TotalFinal: totalPrecio * 1.19, 
    })
    .then(({id}) => {
      console.log(id);
      let orderid = id;
      actualizarStockDb(cartProduct);
      clearCart();
      Navigate(`/order/${orderid}`); 
    })
    .catch(error => console.err);  
  }

  const actualizarStockDb = (cartProduct) => {
    cartProduct.forEach((element) => {
      actualizarStock(element.id, element.quantity);
    });      
  }

  const actualizarStock = (id, quantity) => {
    let product;
    const productCollection = collection(db, 'Products');
    const referenceDoc = doc(productCollection, id);
    getDoc(referenceDoc)
    .then(result => {
        product = {
          id: result.id,
          stock: result.data().stock - quantity,
       }
        updateDoc(referenceDoc, product)
        product.stock < 0 ? swal("No hay stock suficiente", "Gracias", "Error") : swal("Compra realizada", "Gracias", "success");
    })
  } 


  const handleChange = (e) => {
    setForm({
      ...form,
      [e.target.name]: e.target.value
    });
  }

  const handleSubmit = (e) => {
    e.preventDefault();
    finalizarCompra();
  }



  return (
    <>
    <div className="container">
      <h3>Formulario de Envio </h3>
      <form onSubmit={handleSubmit}>
        <label htmlFor='name'>Name</label>
        <input type="text" value={form.name} name= "name" onChange={handleChange} />
        <label htmlFor='email'>Email</label>
        <input type="text" value={form.email} name="email" onChange={handleChange} />
        <label htmlFor='phone'>Phone</label>
        <input type="text" value={form.phone} name="phone" onChange={handleChange} />
        <label htmlFor='city'>City</label>
        <input type="text" value={form.city} name="city" onChange={handleChange} />
        <label htmlFor='address'>Address</label>
        <input type="text" value={form.address} name="address" onChange={handleChange} />
        <label htmlFor='zip'>Codigo de area</label>
        <input type="text" value={form.zip} name="zip" onChange={handleChange} />
        <label htmlFor='state'>Provincia</label>
        <input type="text" value={form.state} name= "state" onChange={handleChange} />
        <label htmlFor='country'>Pais </label>
        <input type="text" value={form.country} name="country" onChange={handleChange} />
        <button type="submit">Enviar</button> 
      </form>
      
    </div>
    </>
  );
}

export default CartFinish;

CodePudding user response:

If the input value is undefined, React will interpret that to mean that the component is uncontrolled. Here's a more minimal example:

const App = () => {
    const [value, setValue] = React.useState();
    return <input value={value} onChange={e => setValue(e.target.value) } />;
};

ReactDOM.createRoot(document.querySelector('.react')).render(<App />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div class='react'></div>

Your props like

value={form.email}

result in those inputs being uncontrolled initially.

Either list all of those values with empty strings in the initial state:

const [form, setForm] = useState({
  email: '',
  // ...

Or alternate with the empty string in the JSX:

<input type="text" value={form.email ?? ''} name="email" onChange={handleChange} />
  • Related