I'm trying to avoid so many child component re-renders, but don't know how to optimize the code bellow:
I have an object with a calendar looking shape like so:
{
2019:{
7:{
1:{
avaliable: false
},
2:{
avaliable: true
}
}
}
}
The Day Component (omitting the setAgenda logic for brevity) :
function Day(props) {
<span style={{ color: props.avaliable ? "blue" : "red" }}>
{props.day}
</span>
}
The Calendar Component:
function Calendar() {
const [agenda, setAgenda] = useState(initialAgenda);
renderMonth = () => {
return(
<>
<Day day={1}
avaliable={agenda["2019"]["7"]["1"].avaliable}
memoized={false}
setAgenda={setAgenda}
/>
<Day day={2}
avaliable={agenda["2019"]["7"]["2"].avaliable}
memoized={false}
setAgenda={setAgenda}
/>
</>
}
return(
<>
{renderMonth()}
</>
)
}
Every time I update the avaliable
property of a single Day, every <Day>
rendered inside the Calendar would be re-rendered. Not only that, but every time any part of the Calendar internal State updates, both <Day>
's are re-rendered too.
Experimenting with useMemo, I came up with this:
const day1 = agenda["2019"]["7"]["1"].avaliable;
const memoDay1 = useMemo(
() => (
<Day day={1} avaliable={day1} memoized={true} setAgenda={setAgenda}/>
),
[day1]
);
So the updated Calendar component looks like this:
function Calendar() {
const [agenda, setAgenda] = useState(initialAgenda);
const day1 = agenda["2019"]["7"]["1"].avaliable;
const memoizedDay1 = useMemo(
() => (
<Day day={1} avaliable={day1} memoized={true} setAgenda={setAgenda}/>
),
[day1]);
const day2 = agenda["2019"]["7"]["2"].avaliable;
const memoizedDay2 = useMemo(
() => (
<Day day={2} avaliable={day2} memoized={true} setAgenda={setAgenda}/>
),
[day2]);
renderMonth = () => {
return(
<>
{memoizedDay1}
{memoizedDay2}
</>
}
return(
<>
{renderMonth()}
</>
)
}
Now the unnecessary re-renders are gone, when I update a single day, only a single <Day>
gets re-rendered and if I update the internal State of the Calendar component, no <Day>
is re-rendered - the desired behavior.
On a real life scenario, creating a variable and manually memoizing every component is impossible, since it's an unknown number of days being rendered on the screen.
What would be the ideal way to do it ?
Use React.memo
as analogue of PureComponent
for functional components:
export default React.memo(function Day({...}) { ... })
Purpose useMemo
is rather caching heavy calculation then preventing re-rendering.