Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

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

reactjs - Strange behaviour of useState React hook

I am facing some very strange behaviour with useState React hook. In the following code (https://codesandbox.io/s/purple-bush-nb5uy?file=/src/index.js):

function App() {
  return (
    <div className="App">
      <Comp flag={true} />
    </div>
  );
}
const Comp = ({ flag }) => {
  const [running, setRunning] = useState(false);
  const [jumping, setJumping] = useState(false);
  console.log('zero');
  
  const setBoth = () => {
    setRunning(true);
    console.log('one');
    setJumping(true);
    console.log('two');
  };

  return (
    <>
      {"running: " + running}
      {"jumping: " + jumping}
      <button onClick={() => setBoth()}>setboth</button>
    </>
  );
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

when we click the button, we get the following sequence into the console:

one
two
zero

I would expect:

zero
one
zero
two

since I think that React re-renders immediately should it find a useState setter and the following code executes after re-render. Moreover, that's the case with my React application:

const [time, setTime] = useState('');
console.log('Hey');
const updateTime = (e) => {
        setTime(e.details);
        console.log('Hello');
    };

    useEffect(() => {
        window.addEventListener("updateTime", updateTime);            
        return () => {
            window.removeEventListener("updateTime", updateTime);
        }
    }, []);

What happens with the above code when updateTime runs and when e.details value is different than state variable time's content:

Hey
Hello

In other words, the re-rendering runs first and the code after the setter runs afterwards. So, why do we have different behaviour in the above cases? What is the explanation and what happens under the hood?


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

1 Reply

0 votes
by (71.8m points)

-First question

According to Dan Abramov (Co-creator: Redux, Create React App.)

Currently (React 16 and earlier), only updates inside React event handlers are batched by default. There is an unstable API to force batching outside of event handlers for rare cases when you need it.

no matter how many setState() calls in how many components you do inside a React event handler, they will produce only a single re-render at the end of the event

and in your first case click event is a react event

-Second question

According to Dan Abramov

However, both in React 16 and earlier versions, there is yet no batching by default outside of React event handlers. So if in your example we had an AJAX response handler instead of handleClick, each setState() would be processed immediately as it happens. In this case, yes, you would see an intermediate state:

window.addEventListener is not a react event, so it should be rendered immediately.

You can found the full anwser of Dan Abramov here

I made an example here containing the two scenarios


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...