Home > database >  React component is re rendering despite using useCallback hook
React component is re rendering despite using useCallback hook

Time:08-07

My code:

App jsx is the parent component

App.jsx|

export default function App() {
  const [selectedUnits, setSelectedUnits] = useState([]);

  const updateSelectedUnits = useCallback((unitId) => {
    const newSelectedUnits = selectedUnits.includes(unitId)
      ? selectedUnits.filter((u) => u !== unitId) // remove item
      : [...selectedUnits, unitId];
    setSelectedUnits(newSelectedUnits);
  }, []);

  return (
    <div className="App">
      <Table updateSelectedUnits={updateSelectedUnits} />
    </div>
  );
}

And,

Table jsx is the child component which is rerendering whenever I clicked on any of the TD. Since, updateSelectedUnits, just update the states, and this state is not passed to child components, I am little confused, why it is still rerendering. On top of that I have also used useCallback, not sure if it is something I have done correctly though.

Table.jsx

import React from "react";

const Table = ({ updateSelectedUnits }) => {
  const handleUnitClick = (event, unitId) => {
    //add class to td
    updateSelectedUnits(unitId);
  };

  console.log("table rerendered");

  return (
    <table>
      <tbody>
        <tr>
          <td onClick={(e) => handleUnitClick(e, "1")}>01</td>
        </tr>
        <tr>
          <td onClick={(e) => handleUnitClick(e, "1")}>02</td>
        </tr>
      </tbody>
    </table>
  );
};

export default Table;

Here, is codesandbox. Table component is rerendering, and I want it to be prevent from rerendering

CodePudding user response:

You can use React.memo to prevent the Table to be re-rendered.

export default React.memo(Table)

CodePudding user response:

It's because you are using react version 18 which mounts the component, unmounts it and then mounts it again you can read more about it in the react doc

I downgraded it to version 17 and it only renders once: codesandbox react v17

It only happens in react 18 if you have StrictMode in index.js, removing it will only render the Table once

CodePudding user response:

<Table/> is always re-rendered because it's a child of <App/>, which gets re-rendered after its state update. There's no workaround about this.

EDIT: To avoid permanent calculation in your Table component, just memoize intensive computations with useMemo().

  const computedData = React.useMemo(()=> {
    console.log("computedData running")
    return ["cool", "data"]
  }, [])

  console.log("computedData", computedData)

You will see that the log computedData will appear as expected after each click on a table cell, but it won't run an intensive computation more than once (the log computedData running will only fire once).

Rendering is not a bad thing. Memoization has a cost and should only be used for intensive computations. Also, add selectedUnits as an array dependency of updateSelectedUnits in App.tsx to avoid any memory leaks.

  • Related