React + Firebase function looping by accident - javascript

I have no idea why is my function looping when I use useStates,
Can anyone figure out the problem.
It loops over and over,this is what appears in my console.log inside the snapshot
`function Classtab() {
const [userName, setuserName] = React.useState(null)
const [userType, setuserType] = React.useState(null)
const [userEmail, setuserEmail] = React.useState(null)
const [userCourse, setuserCourse] = React.useState([])
const [registeredCourse, setregisteredCourse] = React.useState([])
firebase.auth().onAuthStateChanged((user) => {
if(user){
var db = firebase.firestore()
db.collection('user').doc(user.uid)
.get()
.then(snapshot => {
setuserName( snapshot.data().name)
setuserType( snapshot.data().type)
setuserCourse( snapshot.data().course)
setuserEmail( user.email)
console.log(userCourse)
userCourse.map(course => {
db.doc(course).get().then(
snapshot => {setregisteredCourse([...registeredCourse, snapshot.data().name])}
)
}
)
}).catch(error => console.log(error))}else{}
})
return(...)`

You need to move your auth code into useEffect. What's happening right now is that you are running onAuthStateChanged on every render. And each time that returns, it causes another render, causing it to infinitely add more subscriptions.
I've modified your code to prevent the infinite re-renders and allow userCourse to be the correct value in the promise.then function. What it was originally would've had userCourse in the function to always be an empty array (due to the closure).
function Classtab() {
const [userName, setuserName] = React.useState(null);
const [userType, setuserType] = React.useState(null);
const [userEmail, setuserEmail] = React.useState(null);
const [userCourse, setuserCourse] = React.useState([]);
const [registeredCourse, setregisteredCourse] = React.useState([]);
const registeredCourseRef = useRef(registeredCourse);
useEffect(()=>{
registeredCourseRef.current = registeredCourse;
},[registeredCourse])
useEffect(() => {
const unsubscribe = firebase.auth().onAuthStateChanged((user) => {
if (user) {
var db = firebase.firestore();
db.collection('user')
.doc(user.uid)
.get()
.then((snapshot) => {
setuserName(snapshot.data().name);
setuserType(snapshot.data().type);
const userCourse = snapshot.data().course;
setuserCourse(userCourse);
setuserEmail(user.email);
console.log(userCourse);
userCourse.map((course) => {
db.doc(course)
.get()
.then((snapshot) => {
setregisteredCourse((registeredCourse)=>[
...registeredCourse,
snapshot.data().name,
]);
});
});
})
.catch((error) => console.log(error));
} else {
}
});
return () => {
unsubscribe();
};
//Need to have registeredCourse in the dependency array
//Or have it in a ref
}, []);
// return(...)
}

Related

I want to be able to delete an object from the api and re render the function without having to manually refresh the page, how can I do that?

const Notes = () => {
const history = useNavigate();
const [apiData, setApiData] = useState([]);
useEffect(() => {
axios
.get(`https://6390acc765ff4183111b53e9.mockapi.io/notes`)
.then((getData) => {
setApiData(getData.data);
});
}, []);
const onDelete = (id) => {
axios
.delete(`https://6390acc765ff4183111b53e9.mockapi.io/notes/${id}`)
.then(() => {
history("/notes");
});
};
This way I can delete the note that i fetched earlier, but it still appears on the screen until I refresh manually. It doesn't also go to /notes because i am already on /notes
You can either return the updated data in the delete response to update the local state, or you can trigger a refetch of the data after a successful deletion.
Refetch Example:
const Notes = () => {
const history = useNavigate();
const [apiData, setApiData] = useState([]);
const fetchNotes = useCallback(async () => {
const getData = await axios
.get(`https://6390acc765ff4183111b53e9.mockapi.io/notes`);
setApiData(getData.data);
}, []);
useEffect(() => {
fetchNotes();
}, [fetchNotes]);
const onDelete = async (id) => {
await axios
.delete(`https://6390acc765ff4183111b53e9.mockapi.io/notes/${id}`);
fetchNotes();
history("/notes");
};
...
Returned response Example*:
const Notes = () => {
const history = useNavigate();
const [apiData, setApiData] = useState([]);
useEffect(() => {
axios
.get(`https://6390acc765ff4183111b53e9.mockapi.io/notes`)
.then((getData) => {
setApiData(getData.data);
});
}, []);
const onDelete = async (id) => {
const getData = await axios
.delete(`https://6390acc765ff4183111b53e9.mockapi.io/notes/${id}`);
setApiData(getData.data);
history("/notes");
};
...
*Note: This requires updating the backend code to return the updated data in the response.

Getting user ids with react native and firestore

I tried to list the ids of the users under the users folder in the firebase firestore but it didn't work, can you help?
const [users, setUsers] = useState([]);
const getList = () => {
const subscriber = firestore()
.collection('users')
.doc()
.get()
.then(result => {
setUsers(result.data());
});
console.log(users)
return () => subscriber();
}
useEffect(() => {
setisLoading(true)
getList()
setisLoading(false)
}, []);

Firebase realtime not working correctly on React

I'm creating lobby for game and I want to display player list. I'm watching for new players in room.
const [roomUsers, setRoomUsers] = useState([])
useEffect(() => {
if (room)
DB.collection("room_users").where("room_id", "==", room.id)
.onSnapshot((querySnapshot) => {
const newRoomUsers = [];
querySnapshot.forEach((doc) => {
newRoomUsers.push(doc.data());
});
setRoomUsers(newRoomUsers)
});
})
When I join in the second window, the number of players changes but the list updates over time. When I join more times, the list stops updating at all.
<h4>Players list ({roomUsers.length}/4)</h4>
{roomUsers.map(roomUser => (
<PlayerListItem
roomUser={roomUser}
owner={roomUser.uuid === room.owner}
/>
))}
In PlayerListItem component I am fetching the user via uuid
const [user, setUser] = useState(null)
useEffect(() => {
DB.collection('users').where('uuid', '==', roomUser.uuid).get().then(snapshot => {
if (!snapshot.empty)
setUser(snapshot.docs[0].data())
})
}, [])
Then I return the username through the component.
Sometimes the same username appears twice in the list instead of different
Your useEffect is missing the dependencies array. It should also return the cleanup function
useEffect(() => {
if (!room) {
return;
}
const unsub = DB.collection("room_users").where("room_id", "==", room.id)
.onSnapshot((querySnapshot) => {
const newRoomUsers = [];
querySnapshot.forEach((doc) => {
newRoomUsers.push(doc.data());
});
setRoomUsers((currVal) => {
console.log({currVal, newRoomUsers})
const newVal = [] // change this to be correct
return newVal
})
});
return () => unsub();
}, [room])

React hooks FlatList pagination

I am trying to let the FlatList get 20 posts from Firestore and render 20. when the end is reached I would like to call the getPosts method to get the next 20 posts which means I will have to have a way to save the last known cursor. This is what I was trying to do when converting class component to hooks.
Please can someone help me , no one answered my last question about this
const Posts = (props) => {
//How to get 20 posts from firebase and then render 20 more when the end is reached
const [allPosts, setAllPosts] = useState();
const [loading, setLoading] = useState(true)
const [isRefreshing, setRefreshing] = useState(false);
useEffect(() => {
getPosts();
}, []);
const getPosts = async () => {
try {
var all = [];
const unsubscribe = await firebase
.firestore()
.collection("Posts")
.orderBy("timestamp",'desc')
.get()
.then((querySnapshot) => {
querySnapshot.docs.forEach((doc) => {
all.push(doc.data());
});
setLoading(false);
});
setAllPosts(all);
if(currentUser === null){
unsubscribe()
}
} catch (err) {
setLoading(false);
}
};
const onRefresh = useCallback(() => {
setRefreshing(true);
getPosts()
.then(() => {
setRefreshing(false);
})
.catch((error) => {
setRefreshing(false); // false isRefreshing flag for disable pull to refresh
Alert.alert("An error occured", "Please try again later");
});
}, []);
return (
<FlatList
data={allRecipes}
refreshControl={
<RefreshControl
refreshing={isRefreshing}
onRefresh={onRefresh}
/>
}
initialNumToRender={20}
keyExtractor={(item, index) => item.postId}
renderItem={renderItem}
/>
);
}
const Posts = () =>{
const [posts, setPosts] = useState();
const [data, setData] = useState();
const addPosts = posts => {
setData({...data,...posts})
// `setData` is async , use posts directly
setPosts(Object.values(posts).sort((a, b) => a.timestamp < b.timestamp))
};
}
You need to add a scroll event listener here
something like:
const Posts = (props) => {
useEffect(() => {
window.addEventListener('scroll', () => {
if (window.scrollY >= (document.body.offsetHeight + window.innerHeight)) {
// fetch more posts here
}
});
});
// ...rest of the codes
}

How to seperate keys and values from a json and store it in a array using useState hook in react

function Graph() {
const [tcases, setCases] = useState([]);
const [recovered, setRecovered] = useState([]);
const [deaths, setDeaths] = useState([]);
useEffect(() => {
axios
.get("https://disease.sh/v3/covid-19/historical/all?lastdays=all")
.then((res) => {
setCases(Object.values(res.data.cases));
setRecovered(Object.values(res.data.recovered)));
setDeaths(Object.values(res.data.deaths)));
})
.catch((err) => {
console.log(err);
});
}, []);
I have tried the above code..it says cases,recovered and deaths are undefined
API used:click here to see the api
I want it like this ..Please help! :)
tcases=[555,654,941...........]
recovered=[17,18,26.........]
deaths=[28,30,36...........]
Thank you!
function Graph() {
const [tcases, setCases] = useState([]);
const [recovered, setRecovered] = useState([]);
const [deaths, setDeaths] = useState([]);
const [date, setDate] = useState([]);
useEffect(() => {
axios
.get("https://disease.sh/v3/covid-19/historical/all?lastdays=all")
.then(res => {
setCases(JSON.parse(JSON.stringify(Object.values(res.data.cases))));
setDeaths(JSON.parse(JSON.stringify(Object.values(res.data.deaths))));
setRecovered(JSON.parse(JSON.stringify(Object.values(res.data.recovered))));
})
.catch(err => {
console.log(err);
});
}, []);
JSON.stringify returns a string..Inorder to store it in array format we will have to use JSON.parse which returns an object.

Categories

Resources