Home > Software engineering >  state hooks is not updating state on change
state hooks is not updating state on change

Time:08-15

I am building a simple blog app and I am trying to update title of the blog But it is not updating, it is just showing the current state.

I have tried many times by changing the method of setting state but it is still showing that error.

App.js

function BlogDetail() {
    const [blogName, setBlogName] = useState("");


    axios.get("/api/blog_detail/70/").then(res => {

       setBlogName(res.data[0].blog_name)
    })

  const handleChange = (e) => {
    console.log(e.target.value)
    setBlogName({
      ...blogName,
      [e.target.name]: e.target.value
    })
  }

  const saveBlog = (e) => {
   // sending to API
   console.log(blogName)
  }

   return (
       <div>
       <form>

       {blogName}


       <input type="text" name="blogName" value={blogName} onChange={e => handleChange} />

       <button type="submit" onClick={e => saveBlog(e)}>Save</button>


       <form>
       </div>


   )
}

And When I update on change instead of updating on submit

onChange=(e => setBlogName(e.target.value))

Then it is showing

A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined

I have tried many times but it is still not working.

CodePudding user response:

input requires a string as a value, but you are trying to pass an object:

setBlogName({
  ...blogName,
  [e.target.name]: e.target.value
})

instead pass a string:

setBlogName(e.target.value)

Also, you need to execute handleChange function and pass the event param.

onChange={e => handleChange(e)}

Edit:

Looked at it second time and it should be like this:


function BlogDetail() {
    const [blogName, setBlogName] = useState("");

    // without this you override state every time you press a key
    useEffect(() => {
      axios.get("/api/blog_detail/70/").then(res => {

         setBlogName(res.data[0].blog_name)
      })
    }, [])

  const handleChange = (e) => {
    // just use value here
    setBlogName(e.target.value)
  }

  const saveBlog = (e) => {
   // sending to API
   console.log(blogName)
  }

   return (
       <div>
       <form>

       {blogName}

       { /* remember to run the function */ }
       <input type="text" name="blogName" value={blogName} onChange={e => handleChange()} />

       <button type="submit" onClick={e => saveBlog(e)}>Save</button>


       <form>
       </div>


   )
}

CodePudding user response:

Besides the problem that within handleChange you need to pass an an string value to setBlogName you also need to wrap your axios fetch call in a useEffect.

The problem is that everytime you trigger a rerender while calling setBlogName you are calling your API point again and set the value back to the fetched value.

You should prevent that by doing the following ->

useEffect(() => {
  axios.get("/api/blog_detail/70/").then(res => {
     setBlogName(res.data[0].blog_name)
  }), [])

Don't forget to install { useEffect } from 'react'.

And well of course update handleChange ->

const handleChange = (e) => {
    const newBlogPostName = e.target.value
    console.log(newBlogPostName)
    setBlogName(newBlogPostName)
  }

CodePudding user response:

you have not any action in this method. where is the update state?

const saveBlog = (e) => {
   // sending to API
   console.log(blogName)


  }

and in this method you change the string to an object

const handleChange = (e) => {
    console.log(e.target.value)
    setBlogName({
      ...blogName,
      [e.target.name]: e.target.value
    })
  }

CodePudding user response:

so the problem is that your function updates your state to an object and then you want to display that object(not a string property of that object) in the DOM. its wrong because you cant display objects in the DOM in react. in this case, you even get an error because you cant use spread operator on strings. you cant do something like this: ...("test")

  const handleChange = (e) => {
    console.log(e.target.value)
    //the state value will be an object. its wrong. you even get an error 
    because of using spread operator on a string
    setBlogName({
      ...blogName //this is a string at the init time,
      [e.target.name]: e.target.value
    })
  }

so whats the solution? you should update your state to a string or use a string property of the object. something like this:

      const handleChange = (e) => {
        console.log(e.target.value)

        setBlogName("string")
      }

      return (<>{blogName}</>)

thats it.

  • Related