I’m adding a bar animation to reactJsPlaygroundComponent via activeBar state. I’m not able to understand why MemoizedBarAnimation component is being rendered so many times on adding bar although props stay same throughout. Have used useCallback for memoizing remove. Also i’m using areEqual for arePropsEqual? in memo. and in the console.log too i see barEl is same.
Q1. Then why is MemoizedBarAnimation rerendering?
Q2. Sometimes i’m getting this error as well – Cannot update a component (ReactJsPlayground
) while rendering a different component (BarAnimation
).Why is it happening, what possible changes should i be making to make this go away?
import React, { useState, useEffect, useCallback, memo } from "react";
// Custom comparison function for React.memo
const areEqual = (prevProps, nextProps) => {
console.log('areEqual', prevProps.barEl, nextProps.barEl);
return Object.is(prevProps.barEl, nextProps.barEl);
};
const BarAnimation = (props) => {
const { removeBar, barEl } = props;
const [bar, setBar] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setBar((prev) => {
if (prev + 5 > 200) {
clearInterval(id);
removeBar(barEl);
return prev;
}
return prev + 5;
});
}, 100);
return () => {
clearInterval(id);
};
}, [removeBar, barEl]);
console.log("BarAnimation render", props);
return (
<div
style={{ width: `${bar}px`, height: "50px", border: "2px solid black" }}
></div>
);
};
// Memoized component
const MemoizedBarAnimation = memo(BarAnimation, areEqual);
function ReactJsPlayground() {
const [activeBar, setActiveBar] = useState([]);
const [pendingBar, setPendingBar] = useState([]);
const threshold = 5;
const removeBar = useCallback((el) => {
setActiveBar((actBar) => {
let temp = [...actBar];
temp = temp.filter((tel) => tel !== el);
let pbar = [...pendingBar];
while (temp.length < threshold && pbar.length) {
temp.push(pbar[0]);
pbar = pbar.slice(1);
}
setPendingBar(pbar);
return temp;
});
}, [pendingBar]);
const addBar = () => {
if (activeBar.length < threshold) {
setActiveBar((prev) => [...prev, new Date().getTime() + Math.random()]);
} else {
setPendingBar((prev) => [...prev, new Date().getTime() + Math.random()]);
}
};
console.log("ReactJsPlayground render");
return (
<>
<button onClick={addBar}>ADD BAR</button>
<div>
{activeBar.map((el) => (
<MemoizedBarAnimation key={el} barEl={el} removeBar={removeBar} />
))}
</div>
</>
);
}
export default ReactJsPlayground