I'm trying to render out a nested array of objects from my Firebase db. The code for adding the objects into the array works perfectly, but the rendering of the objects doesn't. This is the code for it:
//useStates
const [newTodos, setNewTodos] = useState([]);
const [user, setUser] = useState({});
useEffect(() => {
onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser);
});
}, [])
useEffect(() => {
//get the db user's todos and display them
const getTodos = async () => {
const userDoc = doc(db, "users", user.uid);
const docSnap = await getDoc(userDoc);
const todoList = docSnap.data().todos;
setNewTodos(todoList);
}
getTodos();
}, [])
It gives me this error message:
index.esm2017.js:1020 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'indexOf') at ht.fromString (index.esm2017.js:1020:1) at Da (index.esm2017.js:16739:1) at getTodos (TodoList.js:89:1) at TodoList.js:95:1 at commitHookEffectListMount (react-dom.development.js:23150:1) at commitPassiveMountOnFiber (react-dom.development.js:24926:1) at commitPassiveMountEffects_complete (react-dom.development.js:24891:1) at commitPassiveMountEffects_begin (react-dom.development.js:24878:1) at commitPassiveMountEffects (react-dom.development.js:24866:1) at flushPassiveEffectsImpl (react-dom.development.js:27039:1)
Line 89 is: const userDoc = doc(db, "users", user.uid);
Line 95 is: getTodos();
It worked kind of when I didn't wrap the getTodos
function in the useEffect
, but it breakes when I log in with another user since I render individual todos for each user.
It also kind of worked when I put the getTodos
in a onLoad
in this code (I had to "hack" this part for it to work, but it spat out the same error I have now):
if (newTodos.length == 0) {
return (
<div className="no-todos" onl oad={getTodos}>
<Nav />
<img id="hero-img" src={todopic} alt="todopic" />
<Typography variant="h4">You are all done!</Typography>
</div>
)
//if you have items render this
}else{...}
Edit
I put user
in the dependency array of the useEffect
and it works, but I still get a similar message.
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'indexOf') at ht.fromString (index.esm2017.js:1020:1) at Da (index.esm2017.js:16739:1) at getTodos (TodoList.js:89:1) at TodoList.js:94:1 at commitHookEffectListMount (react-dom.development.js:23150:1) at commitPassiveMountOnFiber (react-dom.development.js:24926:1) at commitPassiveMountEffects_complete (react-dom.development.js:24891:1) at commitPassiveMountEffects_begin (react-dom.development.js:24878:1) at commitPassiveMountEffects (react-dom.development.js:24866:1) at flushPassiveEffectsImpl (react-dom.development.js:27039:1)
Line 94: getTodos
in the useEffect
I also don't get any problems when switching between the users.
CodePudding user response:
Your useEffect that calls getTodos
is called on the first render, and on the first render your user
object is equal to {}
. So when your getTodos
is trying to get user.uid it gets undefined, and looks like this undefined gets handled somehow inside doc
function which leads to your error. The fix is pretty simple:
useEffect(() => {
// due to user can be {} in your case
if (!user || !user.uid) return;
const getTodos = async () => {
const userDoc = doc(db, "users", user.uid);
const docSnap = await getDoc(userDoc);
const todoList = docSnap.data().todos;
// in case todoList is undefined - newTodos will still be an array
// if todos is somehow not an array in firestore - that will not help btw.
setNewTodos(todoList || []);
};
getTodos();
}, [user]); // add user here to trigger useEffect when user object changed