17

UPDATED QUESTION:

If I type something in the input field before I scroll the expanded prop gets set to true - correct

If I scroll down - expanded gets set to false - correct

If I type something in the input field now expanded is still false - I expect expanded to be set to true again.

code:

export default () => {

const [expanded, setExpanded] = useState(true)

let searchInput = React.createRef()
let scrollTopValue = 0;

function handleSearchInput() {
    console.log(Boolean(searchInput.current.value.length))
    setExpanded(Boolean(searchInput.current.value.length)) // first time true, don't get re triggered

}

useEffect(() => {
    window.addEventListener('scroll', handleScroll)
    return () => window.removeEventListener('scroll', handleScroll)
}, []);

function handleScroll() {
    setExpanded(scrollTopValue > document.documentElement.scrollTop)
    scrollTopValue =  document.documentElement.scrollTop
}

return (
<header>
   {expanded? 'expanded': 'nope'}
    <input role="search" ref={searchInput} onChange={handleSearchInput}></input>

</header>)
}
Björn Hjorth
  • 2,459
  • 5
  • 25
  • 31
  • 1
    I didn't see the update. Do you mean that `{expanded? 'expanded': 'nope'}` doesn't work as intended? There are no problems with it in the code you posted. – Estus Flask Mar 16 '19 at 08:56
  • 1
    Updated question, hope I explain myself better – Björn Hjorth Mar 16 '19 at 10:00
  • 1
    I'll undupe the question in case you have problems unsolved and try to answer it. But from what I see, there are no problems. Both change and scroll handlers update the state as expected, https://stackblitz.com/edit/react-ccv6dh . This cannot be replicated, *If I type something in the input field now expanded is still false*. – Estus Flask Mar 16 '19 at 10:15
  • 1
    Thank you for the code, I must have some other error I am not aware of. Thank you for your time I will have a look and see what is different in my pipeline – Björn Hjorth Mar 16 '19 at 10:18
  • 1
    You're welcome. Feel free to ping me if you will come up with an example that can replicate the problem. – Estus Flask Mar 16 '19 at 10:23
  • @estus I can add you as an collaborator to my github, what is your username? – Björn Hjorth Mar 17 '19 at 08:00
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/190185/discussion-between-bjorn-hjorth-and-estus). – Björn Hjorth Mar 17 '19 at 08:04
  • ok no problem, I have added you as collaborator. you can find the code here: https://github.com/Kaffesumpen/sagohornan/blob/master/src/components/header/header.js – Björn Hjorth Mar 17 '19 at 17:29
  • I made some troubleshooting, if I remove everything in the if statetment on row 86 it all works as it should, maybe that helps. ( this is my first try on React as I am a Angular guy in the office) – Björn Hjorth Mar 17 '19 at 17:31
  • 1
    Just checked it. Scroll listener is retriggered on component update for some reason and overrides `expanded` every time it's changed by input. Not sure why exactly this happens in this layout but this is not totally unexpected. A solution is to either call setExpanded only when both scrollTopValue and document.documentElement.scrollTop change, e.g. with useMemo. Or more likely, to keep scroll and input states as different states and derive `expanded` from them, so input state could take precedence, something like `expanded = isInput || !isScrolledDown`. – Estus Flask Mar 18 '19 at 11:30

1 Answers1

7

Updating state in react is not guaranteed synchronous call. So, when you are calling console.log(expanded) just after changing state it won't return the new state. Your component will receive new state on the re-render.

You can also refer to this blog https://medium.com/@wereHamster/beware-react-setstate-is-asynchronous-ce87ef1a9cf3

Another reference:- useState set method not reflecting change immediately

cEeNiKc
  • 1,308
  • 7
  • 13
  • 2
    could you please help on what would be solution to update a boolean value? i have tried every solution in those links but nothing seems to work. I am using useEffect() to detect the change and inside useEffect the change is happenening, but when i am using the value to make an api request, the boolean value that changed is still in the previous state. – Hisham Hafeel Jul 11 '21 at 10:58
  • can you please post it as a separate question with more details and link the question in the comments here – cEeNiKc Jul 13 '21 at 07:00
  • @HishamHafeel I have the same issue. The changed state renders but it is still the same while making the API call. Did you solve it? – Junaid Oct 10 '21 at 09:06
  • @Junaid can you please create a separate question with the details of the issue you are facing and link it to me so I can check – cEeNiKc Oct 12 '21 at 07:37