The code below will render a <h1>
and two <button>
.
In my expectation , the changeString1
<button>
will change letString
to 1
and change <h1>
text to 1
finally, while the changeString2
<button>
will
<h1>
text to 3
if I click the changeString2
first <h1>
text to 1
if I click the changeString1
first But in fact
changeString1
once first, then click the changeString2
, <h1>
text will be 3
! But why? changeString1
twice first, then click the changeString2
, <h1>
text will be 1
! But why? It seems that both of 2 facts are contradictory...
You can test this by https://codesandbox.io/s/wy4l1y4o8
import React, { useState } from "react";
import ReactDOM from "react-dom";
function App() {
let letString = "3";
const [statString, setStatString] = useState("2");
function changeString1() {
letString = "1";
setStatString(letString);
}
function changeString2() {
console.log(letString);
setStatString(letString);
}
return (
<div>
<h1>{statString}</h1>
<button onClick={changeString1}>changeString1</button>
<button onClick={changeString2}>changeString2</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Please look at the flow that is taking place:-
1st click on changeString1
state changes
component re renders
letString gets re-initialized to 3 because of let letString = "3"
value of letString = 3;
value of statString = 1 (state);
2nd click on changeString1
value of letString gets set to 1 in the function call;
But value of statString(state) is already 1 so no state changes and component never re-renders and letString is not re-initialized
After 2nd click values are:-
letString = 1;
statString = 1(state);
Now, when you click on changeString2 value of letString is 1 and statString is also 1 so state doesn't changes and nothing happens and you just see 1.
When you click on changeString2 , local variable letString value is 3.
If you want to persist letString value between render cycles you must use useState or even using a global scope variable (not recommended)
You should track clicking on changeString1 in a separate variable:
const {useState} = React function App() { const [statString, setStatString] = useState("2"); const [clicked, setClicked] = useState(false) function changeString1() { setClicked(true) setStatString("1"); } function changeString2() { setStatString(clicked ? "1" : "3"); } return ( <div> <h1>{statString}</h1> <button onClick={changeString1}>changeString1</button> <button onClick={changeString2}>changeString2</button> </div> ); } const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script> <div id="root" />
The reason your code didn't work as expected is that each invocation of App
creates a new instance of the letState
variable that is bound to changeString2
function when it is defined . React optimizes calls that don't change the state, avoiding unnecessary re-renders. So when you click the second time you are not causing a replacements of the callback functions. So when you click on changeState2
it's the same function defined in "previous" render.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.