Reputation: 21
I'm using a useEffect hook inside my React component which is updating a local state when there is any change in global redux state.
This is my component which is trying to update imgList when we gets updated photos using useSelector. But the website is crashing due to the error 'Maximum call stack size exceeded'. useEffect is running again and again which shouldn't happen since photos only gets updated once.
import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { fetchDataHandler } from "./store/actions";
const PhotoWrapper = () => {
const dispatch = useDispatch();
const [imgList, setImgList] = useState([]);
const photos = useSelector((state) => ({ ...state.data }));
useEffect(() => {
dispatch(fetchDataHandler());
}, [dispatch]);
/* useEffect which is causing website crashing */
useEffect(() => {
const topImages = photos[0]?.map((photo) => (
<img src={photo?.url} alt={photo?.title} />
));
setImgList(() => topImages);
}, [photos]);
return <div>{imgList}</div>;
};
export default PhotoWrapper;
Here is the link to the codesandbox to generate error.
Upvotes: 2
Views: 942
Reputation: 499
Please update your code to the following:
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchDataHandler } from './store/actions';
const PhotoWrapper = () => {
const dispatch = useDispatch();
const photos = useSelector((state) => state.data);
useEffect(() => {
dispatch(fetchDataHandler());
}, [dispatch]);
return (
<div>
{photos[0]?.map((photo) => (
<img src={photo?.url} alt={photo?.title} />
))}
</div>
);
};
export default PhotoWrapper;
Or to this:
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchDataHandler } from './store/actions';
const PhotoWrapper = () => {
const dispatch = useDispatch();
const [imgList, setImgList] = useState([]);
const photos = useSelector((state) => state.data);
useEffect(() => {
dispatch(fetchDataHandler());
}, [dispatch]);
/* useEffect which is causing website crashing */
useEffect(() => {
const topImages = photos[0]?.map((photo) => ({ url: photo?.url, title: photo?.title }));
setImgList(() => topImages);
}, [JSON.stringify(photos)]);
return (
<div>
{imgList.map((el, i) => (
<img key={i} src={el?.url} alt={el?.title} />
))}
</div>
);
};
export default PhotoWrapper;
Upvotes: 0
Reputation: 41893
Except that you shouldn't really map JSX inside the useEffect
, the problem is that you are spreading the information from the store.
const photos = useSelector((state) => ({ ...state.data }));
// ^^^^^^^^^
So with every re-render, you have a different instance of photos
(because of spread) and you are ending up with an infinite loop.
Just remove the spread to get rid of the error.
const photos = useSelector((state) => state.data);
Upvotes: 3