I have a collection of profile documents in firebase and I want to render them in the profiles page, however after I have updated the userProfiles state and use useDispatch to store the state in the slice, I get an infinite loop when rendering the profile page.
I have tried putting the dispatch() into a useEffect, not in a useEffect and inside the querySnapshot promise but I’m still getting an infinite loop wherever I put it.
Any feedback is appreciated, thank you.
\ profiles.js
export const Profiles = () => {
const [userProfiles, setUserProfiles] = useState([]);
const dispatch = useDispatch();
const navigate = useNavigate();
const user = useSelector(selectUser);
db.collection("customers")
.doc(user.info.uid)
.collection("profiles")
.get()
.then((querySnapshot) => {
const documents = querySnapshot.docs.map((doc) => doc.data());
setUserProfiles(documents);
});
useEffect(() => {
dispatch(profiles(userProfiles));
}, []);
console.log({ userProfiles });
return (
<div className="profile_container">
<h1 className="profile_title">Who's Watching?</h1>
<div className="profile_row">
{userProfiles.map((profile) => {
return (
<div className="profile_individualProfile">
<img
src="https://occ-0-300-1167.1.nflxso.net/dnm/api/v6/K6hjPJd6cR6FpVELC5Pd6ovHRSk/AAAABY5cwIbM7shRfcXmfQg98cqMqiZZ8sReZnj4y_keCAHeXmG_SoqLD8SXYistPtesdqIjcsGE-tHO8RR92n7NyxZpqcFS80YfbRFz.png?r=229"
alt="profile"
/>
<p>{profile.name}</p>
</div>
);
})}
<div
onClick={() => navigate("/add-profile")}
className="profile_addProfile_container"
>
<img
src="https://img.icons8.com/ios-glyphs/30/FFFFFF/plus--v1.png"
alt="add profile"
/>
<h2>Add Profile</h2>
</div>
</div>
</div>
);
};
\ userSlice.js
export const userSlice = createSlice({
name: "user",
initialState: {
user: {
info: null,
profiles: [],
},
},
reducers: {
login: (state, action) => {
state.user.info = action.payload;
},
logout: (state) => {
state.user.info = null;
},
profiles: (state, action) => {
state.user.profiles.push(action.payload);
},
},
});
2
Answers
For anyone that runs into this issue you may find this useful. Following from yilmaz's helpful answer, I had to update the Profiles.js and userSlice.js as follows...
In the current implementation, when your page is rendered,
db.collections
runs and you set statesetUserProfiles(documents)
which renders your app and againdb.collections
runs. to prevent this you should rundb.collections
inuseEffect
.have another useEffect
this will NOT work neither.
setUserProfiles
will be causing issue. Because when app renders, you fetch data, you set the state, change theuserProfiles
, this will rerender app again.The problem with your code is you do not need
setUserProfiles
. instead indb.collections()
when you get the documents, you dispatch the documents and then access the profiles from redux withuseSelector
Now use
useSelector
to reach the state inredux
now when you use map guard your app