I know that this question has been asked multiple times, but I am trying to understand the logic behind react rendering decisions when there is a change in state and how I should correctly write "reactly".
This is my code:
// Parent.js
import React, { useEffect, useState } from "react";
import ComponentA from "./ComponentA";
import ComponentB from "./ComponentB";
export default function App() {
const [a, setA] = useState(false);
const [b, setB] = useState(false);
const onClickA = () => {
setA((p) => !p);
};
const onClickB = () => {
setB((p) => !p);
};
useEffect(() => {
console.log("Parent rendered");
});
return (
<div>
<ComponentA value={a} onClick={onClickA} />
<ComponentB value={b} onClick={onClickB} />
</div>
);
}
// Child A
import React, { useEffect } from "react";
export default function ComponentA(props) {
useEffect(() => {
console.log("A rendered");
});
return (
<button onClick={props.onClick}>Button A - {props.value.toString()}</button>
);
}
// Child B
import React, { useEffect } from "react";
export default function ComponentB(props) {
useEffect(() => {
console.log("B rendered");
});
return (
<button onClick={props.onClick}>Button B - {props.value.toString()}</button>
);
}
So, when I either click button A or button B, the parent component will re-render causing both ComponentA and ComponentB to re-render even though each one's UI is unrelated to the other's state. I was thinking that react will understand that if I click button A, only the a
state variable is changed, and <ComponentB />
does not depend on a
state so there is no need to re-render it again, because its props
remained unchanged. So I think that this code is wrong and should be written in a different style but I cannot figure this out.
Obviously, I thought that since a
does not affect <ComponentB />
and b
does not affect <ComponentA />
, then why don't I just pass the state to each component separately ? This way, each component will be responsible for its own re-rendering. But then I thought, what if in the future ComponentA
depends on b
or ComponentB
depends on a
? I cannot change the code each time I want to share the state, writing callback functions and transforming state into props and vice versa.
Is there any better way that provides this kind of flexibility without too much overhead code (ex redux) ?
That's just the key concept of react. If a component rerenders, per default all children will rerender. This is not a concern, because it is usually very fast - unless you do expensive computations in your render functions, which you shouldn't.
There are some escape hatches like React.memo
and the shouldComponentUpdate
class lifecycle function, but usually you should not need them and premature optimizations are aftentimes more hurtful than useful.
If you have performance problems, measure them and then optimize the problems you spot there. Otherwise, don't sweat rerenders too much.