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.