2

I'm building my website with React, and I'm using useState to get the id of hovered item.

But when I use setState to get the value, it doesn't update and remain 'null'

So on console, I can see the event.target.id is recognized, but even after the setState event, the state value return null.

Can anybody give some clues on what is happening here?

Here's the code

import React from 'react'
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
import styled from 'styled-components'



const WorksTitle = props => {
  const { type, title, imgSrc, link, year } = props
  const [currentMenu, setCurrentMenu] = React.useState(null)

  const handleHover = event => {
    console.log(
      'event target: ',
      event.target,
      ' / ',
      'event target id: ',
      event.target.id
    )
    **console.log(event.target.id)
    setCurrentMenu(event.target.id)
    console.log(currentMenu)**
  }

  const handleMouseOut = event => {
    console.log('mouse out from:', event.target.id)
    setCurrentMenu(null)
  }

  return (
    <StyledWorksTitle>
      <TitleItem id={title} onMouseOverCapture={handleHover} onMouseOut={handleMouseOut}>
        <div className={`itemWrapper ${(currentMenu === { title } ||
            currentMenu === null) && 'activated'}`}
          id={title}>
          <Link to={link}></Link>
        </div>
      </TitleItem>
    </StyledWorksTitle>
  )
}

/* styled-components */

export default WorksTitle

  • Does this answer your question? [useState set method not reflecting change immediately](https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately) – goto Feb 16 '20 at 13:58

2 Answers2

2

setState is an async call which means the console.log immediately after it wont have the updated value. For debugging purposes do this: right after StyledWorksTitle create a button and write in it like this:

   <button onClick={()=>console.log(currentMenu)}></button>

You should be able to see your updated value now.

As to how to handle its implementation. I would recommend using useEffect() and passing the currentMenu state as its dependency.

   useEffect(()=>{
    //write a function to push hovered item id into an array or something
   },currentMenu)

This is very generic because i dont know what you want to do with the ID but in anycase this will help you in your path.

Hadi Pawar
  • 1,090
  • 1
  • 11
  • 23
  • Even though the state updater function runs asynhronously that does not explain the behavior of the code in this case. The reason why you still get the old value of the state after calling setCurrentMenu is because of ***closure***. So the reasoning for your answer is incorrect. You might want to update your answer on that fact – Chitova263 Feb 16 '20 at 14:20
-1

useState is asynchronous so currentMenu isn't updated until the next render.

Here is a sandbox example to demonstrate.

Jacob
  • 887
  • 1
  • 8
  • 17
  • even though the updater function is aynchronous that does not explain the behaviour in the above code. This is because of ***closure***. In react props and state and are immutable and each render has its own props and state and event handlers. So in this case you will still get the old state value since its the one your event handler ***closes** over – Chitova263 Feb 16 '20 at 14:27
  • I see what you mean, however, this is technically not quite true. You can bypass this by assigning to state directly. This will update in the console.log directly under, showing that it mutated state. I know this goes against everything react but just a example. [here](https://codesandbox.io/s/elated-wiles-9j6gb) – Jacob Feb 16 '20 at 14:39