I was always under the assumption that React updates the UI only when I make immutable changes to the state. Recently I came across a snippet that did something I didn’t expect:
import { useState } from "react";
import "./App.css";
function App() {
const [strings, setStrings] = useState<string[]>([]);
const [inputValue, setInputValue] = useState("");
return (
<>
<input
type="text"
onChange={(e) => {
strings[strings.length] = e.target.value;
setInputValue(e.target.value);
}}
/>
<ul>
{strings.map((s) => {
return <li>{s}</li>;
})}
</ul>
</>
);
}
export default App;
I expected that the list would not update when I enter values in input, as I am making mutable changes to the strings
variable, and as React uses object references to compare and update the DOM, there would be no changes in the list.
But the list updates whenever there’s a change in the input.
The same lists will not update if I define the strings
variable as a normal javascript array and not as React state:
import { useState } from "react";
import "./App.css";
function App() {
// const [strings, setStrings] = useState<string[]>([]);
let strings: string[] = [];
const [inputValue, setInputValue] = useState("");
return (
<>
<input
type="text"
onChange={(e) => {
strings[strings.length] = e.target.value;
setInputValue(e.target.value);
}}
/>
<ul>
{strings.map((s) => {
return <li>{s}</li>;
})}
</ul>
</>
);
}
export default App;
Looks like my understanding of how React updates and compares states and js variables between virtual doms is lacking, please help!
How exactly does React compare the states? I am under the assumption that it is using the Object.is method underneath to compare objects, in which case, how does it know that the state changed when I am keeping the object reference same?
CodeSandbox Repo for your reference.
Edit: I know that I am forcing a re-render with the line setInputValue(e.target.value);
, but I am essentially trying to understand how exactly React compares states when it is re-rendering. How would React know that strings
state has changed without its object reference changing?
2
Answers
Well, you are updating the state with the
setInputValue
call, so React rerenders your component (and it therefore sees the updated version ofstrings
). So the first example is working only by accident, because you change another state at the same place.The second example doesn’t work because the
strings
variable is reset at each new render.Actually in your code. the React re-render because the
inputValue
changed.You can try to only mutate
strings
in youronChange
code withoutsetInputValue
, and it should not re-render as before.