1

The following component is supposed to:

  1. Get a single letter from an api call
  2. Append it to the string and display it

Problem: when I press the button quickly a couple of times the string is only updated with 1 letter Expected result: The string gets updated with the same number of letters as button clicks, no matter how frequent the clicks are

I understand that the issue is that the closure keeps a reference to the old letters variable that's in state. But how do I solve this with hooks? I rewrote this to a class component and it worked there, but that's because this.state.letters was not in a closure.

Press "Run code snippet" to test.

function getRandomLetter() {
  return 'abcdefghijklmnopqrstuvwxyz'[new Date() % 26]
}

function apiCreateNextLetter() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(getRandomLetter())
    }, 1000)
  })
}

function Alphabet() {
  const [letters, setLetters] = React.useState('')

  function getNextLetter() {
    apiCreateNextLetter().then(nextLetter => {
      setLetters(letters + nextLetter)
    })
  }

  return (
    <div>
      <button onClick={getNextLetter}>
        Get next letter
      </button>
      <span>
        Letters: {letters}
      </span>
    </div>
  )
}

ReactDOM.render(<Alphabet />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script><div id="app"></div>
Ziarno
  • 7,366
  • 5
  • 34
  • 40
  • Does this answer your question? [State not updating when using React state hook within setInterval](https://stackoverflow.com/questions/53024496/state-not-updating-when-using-react-state-hook-within-setinterval) – Brian Thompson Feb 05 '20 at 20:49
  • yes, thanks! Didn't know about this form – Ziarno Feb 05 '20 at 20:59

1 Answers1

4

Use the updater form...

setLetters(prevLetters => prevLetters + nextLetter)
Brian Thompson
  • 13,263
  • 4
  • 23
  • 43