Search code examples
reactjsstateuse-effectrerender

Re rendering of the component is being required to update state in React


I am trying to do crud operation through json-server. The server looks like:

   {
  "product": [
    {
      "prod_name": "Product1",
      "prod_price": "23451",
      "prod_desc": "Lorem Ipsum",
      "id": 1
    },
    {
      "prod_name": "Product2",
      "prod_price": "12345",
      "prod_desc": "Lorem Ipsum",
      "id": 2
    }
  ]
}

It is working fine for get,post and delete. For edit I was sending the id through url, after receiving it I am trying to fetch the particular product using id, so that I can do the state update and using that state I will show the previous value in value attribute.

function EditProduct() {
    const {pid}=useParams();
    const [state,setState]=useState({})
    const getProduct=async()=>{
        const response=await axios.get(`http://localhost:1000/product/${pid}`)
        return response;
    }
    useEffect(()=>{    
    getProduct().then(res=>{            
            console.log("Data to be edited: ",res.data)
            setState(res.data)
            console.log("Product: ",state);
        })
        .catch(res=>{
            console.log("Error to find the product")
        })    
    },[])

    const handleSubmit=(event)=>{

    }
  return (
    <div>
        <form onSubmit={handleSubmit}>
        <input type="text" name="prod_name" value={state.prod_name} onChange={(event)=>setState({prod_name:event.target.value})}/><br/><br/>
        <input type="text" name="prod_price" value={state.prod_price} onChange={(event)=>setState({prod_price:event.target.value})}/><br/><br/>
        <input type="text" name="prod_desc" value={state.prod_desc} onChange={(event)=>setState({prod_desc:event.target.value})}/><br/><br/><br/>
        <input type="submit" value="Add" />
        </form>
    </div>
  )
}

But the state updation is creating a problem. whenever the component is rerendering the state updation is happening.But until the rerendering it is showing blank. Is there any solution? What is the problem in my code?


Solution

  • Problem is inside your change handlers, you are not doing state update properly. setState must receive whole object, not just one field as you are doing right now - thus forcing all other fields to be deleted whenever you update one field.

    Rewrite to this:

    <input type="text" name="prod_name" value={state.prod_name} onChange={(event)=>setState(prev => ({...prev, prod_name:event.target.value}))}/><br/><br/>
        <input type="text" name="prod_price" value={state.prod_price} onChange={(event)=>setState(prev => ({...prev, prod_price:event.target.value}))}/><br/><br/>
        <input type="text" name="prod_desc" value={state.prod_desc} onChange={(event)=>setState(prev => ({...prev, prod_desc:event.target.value}))}/><br/><br/><br/>
    

    You will notice how I used prev inside setState callback, and using that prev you are retaining part of the old sate while updating just one desired field.