I have built a React component which has two children: one displays a graph (vis.js) and when the user hovers over a node in the graph, the main component is made aware of this by a state change. The only child using this state is a div (sibling to the graph).
However, when the state changes, all children (including the graph) are re-rendered. I do not want to render the graph every time I hover over a node, just its sibling.
This is my code:
import React, { useState } from "react";
...
const Graph = (props) => {
...
const [nodeName, setNodeName] = useState("");
function handleHoverEvent(node) {
if (nodeName !== node) {
setNodeName(node);
}
}
function makeNodes() {
...
}
function makeEdges() {
...
}
return (
<div>
<Vis
nodes={makeNodes()}
edges={makeEdges()}
OnHover={handleHoverEvent}
/>
<NameDisplay name={nodeName} />
</div>
);
}
...
export default Graph;
makeNodes() and makeEdges() do not depend on the state in any way.
How can I prevent the graph from being re-rendered every time? All I need to do is "shovel" data from one child to another, while only updating one of them.
All it took was to convert all components to ES6 classes. This is described here: https://reactjs.org/docs/state-and-lifecycle.html#converting-a-function-to-a-class
I did not even have to specify a shouldComponentUpdate() method.
You can use React.memo(), React.useCallback for avoiding re-rendering stuff in react component. Avoiding React component re-renders with React.memo
Example :
Button
import React from "react";
interface IProps {
handleClick: () => void;
children: any;
}
function Button({ handleClick, children }: IProps) {
console.log("Rendering button - ", children);
return <button onClick={handleClick}>{children}</button>;
}
export default React.memo(Button);
Count
import React from "react";
import Button from './Button'
interface IProps {
text: any;
count: any;
handleClick: () => void;
children: any;
}
function Count({ text, count, handleClick, children }: IProps) {
console.log(`Rendering ${text}`);
return (
<div>
<div>
{text} - {count}
</div>
<Button handleClick={handleClick}>{children}</Button>
</div>
);
}
export default React.memo(Count);
ParentComponent
import React, { useState, useCallback } from "react";
import Count from "./Count";
export const ParentComponent = () => {
const [age, setAge] = useState(25);
const [salary, setSalary] = useState(50000);
// const incrementAge = () => {
// setAge(age + 1)
// }
// const incrementSalary = () => {
// setSalary(salary + 1000)
// }
const incrementAge = useCallback(() => {
setAge(age + 1);
}, [age]);
const incrementSalary = useCallback(() => {
setSalary(salary + 1000);
}, [salary]);
return (
<>
<Count text="Age" count={age} handleClick={incrementAge}>
Increment Age
</Count>
<Count text="Salary" count={salary} handleClick={incrementSalary}>
Increment Salary
</Count>
</>
);
};