Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
3.6k views
in Technique[技术] by (71.8m points)

reactjs - useState not updating on javascript event

I'm having trouble getting the "set" function of useState to work as I need. I would like to be able to use a keyboard listener to increment a counter, but even though the keyListener function is executing, selection doesn't grow past 1.

Is this an asynchronous updating issue?

To demonstrate my problem, I made the following glitch project. (To use, click on the yellow background and press keys to increment the selection counter.)

import React, { useState } from 'react';

function App() {
  const [selection, setSelection] = useState(0)
  
  const attachKeyListener = () => { 
    console.log("attaching listener")
    document.addEventListener("keydown", keyListener) 
  };
  
  const keyListener = (e) => {
    console.log("increasing selection")
    let tmp = selection + 1
    setSelection(tmp)
  };

  return (
    <div className="App" onClick={attachKeyListener} style={{background:"yellow"}}>
      Counter: {selection} 
    </div>
  );
}

export default App;

live example: https://gaudy-brave-tenor.glitch.me


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You're currently attaching a new listener every time the div is clicked. Instead, add the listener just once, on initial mount, and use the callback form to ensure you have the up-to-date selection when setting anew:

function App() {
  const [selection, setSelection] = React.useState(0)
  React.useEffect(() => {
    console.log("attaching listener")
    const keyListener = (e) => {
      console.log("increasing selection")
      let tmp = selection + 1
      setSelection(selection => selection + 1)
    };
    document.addEventListener("keydown", keyListener) 
  }, []);
  
  return (
    <div className="App" style={{background:"yellow"}}>
      Counter: {selection} 
    </div>
  );
}

ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class='react'></div>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...