I am creating a todolist app paired with Google Firebase to store my data. In the app, you can create projects to organise your tasks. I am using useContext to have my projects accessible accross all the components of my app. My context uses a custom hook to make a call to firebase when mounting to get the projects of the logged in user (or an empty array if the user hasn't got any projects stored in firebase).
My issue is that my contextProvider goes into a mounting loop, making a new call to firebase to set the projects every time it mounts (even though the projects are not changing). The context is actually working in my app, I only realised it was looping because I have reached the maximum amount of calls that can be made to firebase on the freeplan in a day.
Here's my code for for the context:
import React, { createContext, useContext } from "react";
import PropTypes from "prop-types";
import { useProjects } from "../Hooks/index";
export const ProjectsContext = createContext();
export const ProjectsProvider = ({ children }) => {
const { projects, setProjects } = useProjects();
return (
<ProjectsContext.Provider value={{ projects, setProjects }}>
{children}
</ProjectsContext.Provider>
);
};
export const useProjectsValue = () => useContext(ProjectsContext);
and here is my code for the custom hook useProjects() that makes a call to firebase to retrieve the projects:
export const useProjects = () => {
const [projects, setProjects] = useState([]);
useEffect(() => {
db.collection("projects")
.where("userId", "==", "uBnTwu5ZfuPa5BE0xlkL")
.orderBy("projectId")
.get()
.then((snapshot) => {
const allProjects = snapshot.docs.map((project) => ({
...project.data(),
docId: project.id,
}));
if (JSON.stringify(allProjects) !== JSON.stringify(projects)) {
setProjects(allProjects);
}
});
}, [projects]);
return { projects, setProjects };
};
Also, I am console logging in the hook and in the context to check how many times it is beeing called, is it good practice or is there a better way to check how many times a component mounts ?
Thanks in advance
Your code gets stuck into a loop because the
useEffecthook containsprojectsas a dependency. As the code in theuseEffectupdatesprojects, your code gets stuck in a endless cycle of state update and re-render.Looking at your code, it seems that
useEffectusesprojectsin theifstatementand that seems like something you shouldn't be doing in the first place.
You could observe the
projectscollection if you always want to receive real-time updates, otherwise theuseEffecthook should only run once.useEffectusessetProjects()function but it is guaranteed to not change, so adding or omitting it from the dependency array of theuseEffecthook won't make a difference.