skip to Main Content

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


  1. Well, you are updating the state with the setInputValue call, so React rerenders your component (and it therefore sees the updated version of strings). 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.

    Login or Signup to reply.
  2. Actually in your code. the React re-render because the inputValue changed.
    You can try to only mutate strings in your onChange code without setInputValue, and it should not re-render as before.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search