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
useEffect
hook containsprojects
as a dependency. As the code in theuseEffect
updatesprojects
, your code gets stuck in a endless cycle of state update and re-render.Looking at your code, it seems that
useEffect
usesprojects
in theif
statementand that seems like something you shouldn't be doing in the first place.
You could observe the
projects
collection if you always want to receive real-time updates, otherwise theuseEffect
hook should only run once.useEffect
usessetProjects()
function but it is guaranteed to not change, so adding or omitting it from the dependency array of theuseEffect
hook won't make a difference.