skip to Main Content

let’s say we have an array of ids [100, 101, 102] as the current state and we use this ids as key attributes when constructing a list of li item. If we add a new id into the array as [100, 101, 102, 103], then of course React can know that it only need to constuct a new item corresponding to 103 therefore minimize DOM manipulation.

But what if click a button to reverse the array, so it is [102, 101, 100], since the position change, even though we do supply keys, can React be smart enough to know that it doesn’t need to construct 3 new li items, just need to re-order 3 exsiting ones?

4

Answers


  1. Yes, React is made to refresh the DOM quickly and to improve re-renders. When you invert the array in the scenario you described, React can intelligently identify that the overarching items haven’t changed, but the essential characteristics have. As a result, React will rearrange the current <li> items rather than creating new ones.

    The virtual DOM representations of the past and present are compared by React using a reconciliation method called "diffing" to find the bare minimum of changes needed to update the actual DOM. React can keep track of an element’s identity across renderings thanks to the keys supplied to it. React utilises a diffing method when it comes across a list of keys, trying to match and reorder the items based on their keys rather than rebuilding them.

    Login or Signup to reply.
  2. Reordering items would effect sure, and rendering would be slow than when its int the first order state.

    read this from documentation:

    As a last resort, you can pass an item’s index in the array as a key. This can work well if the items are never reordered, but reorders will be slow.

    Reorders can also cause issues with component state when indexes are used as keys. Component instances are updated and reused based on their key. If the key is an index, moving an item changes it. As a result, component state for things like uncontrolled inputs can get mixed up and updated in unexpected ways.

    Anyway, avoid using indexes when rendering lists, use instead a unique string to do so, because indexes could causes unwanted issues.

    Login or Signup to reply.
  3. Yes, react is smart enough to know that it does not need to re create three new items, it will just update the correct elements.

    You can see it here in the sandbox I forked from the react docs. In this example, two counters are rendered with two unique stable keys. You can try updating the both counters, and then hit the switch order button, react will switch the counters and maintain the counts correctly, because it is not recreating the counters but updating them based on there positions in UI tree, which remain the same due to the stable key provided.

    Login or Signup to reply.
  4. When you add or reverse the list of items, the entire <ol> or <ul> will be re-rendered in full.

    Even if you memoize the list, it will still render every item within it, since you will be calling Array.prototype.map on the entire list each time you render it.

    const { useCallback, useEffect, useMemo, useState } = React;
    
    const fetchData = () => Promise.resolve([100, 101, 102]);
    
    const Item = ({ text }) => {
      console.log(`Rendering ${text}...`);
      return <li>{text}</li>
    };
    
    const App = () => {
      const [items, setItems] = useState([]);
      
      useEffect(() => {
        fetchData().then(setItems);
      }, []);
      
      const handleAdd = useCallback(() =>
        setItems(currItems => [...currItems, Math.max(...currItems) + 1]), []);
    
      const handleReverse = useCallback(() =>
        setItems(currItems => [...currItems].reverse()), []);
    
      const List = useMemo(() => {
        console.log(`Rendering list of ${items.length} items...`);
        return (
          <ul>
            {items.map(item => (
              <Item key={item} text={item} />
            ))}
          </ul>
        )
      }, [items]);
    
      return (
        <div className="App">
          {List}
          <div className="controls">
            <button type="button" onClick={handleAdd}>Add</button>
            <button type="button" onClick={handleReverse}>Reverse</button>
          </div>
        </div>
      );
    };
    
    ReactDOM
    .createRoot(document.getElementById("root"))
    .render(<App />);
    *, *::before, *::after { box-sizing: border-box; }
    html, body, #root, .App { width: 100%; height: 100%; margin: 0; padding: 0; }
    .App { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; padding: 0.5rem; gap: 0.5rem; }
    .App ul { list-style-type: none; display: flex;  margin: 0; padding: 0; gap: 0.5rem; }
    .App ul li { margin: 0; padding: 0; }
    .App .controls { display: flex; gap: 1rem; }
    .App .controls button { min-width: 4rem; }
    
    .as-console-wrapper { max-height: 8rem !important; }
    <div id="root"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search