I'm trying to get a doc value from firebase using the getDoc() method. It's working. But can't save on useState() hook in ReactJS
Here is my code:
const [post, setPost] = React.useState(null);
React.useEffect(() => {
const fetchPost = async () => {
const docSnap = await getDoc(doc(db, "posts", id));
setPost(docSnap.data())
}
return () => fetchPost();
}, []);
Related
I want to get news but i have an empty dictionary in the first render.
My useEffect
const [news, setNews] = useState({});
const [page, setPage] = useState(1);
const [user, setUser] = useState({});
useEffect(() =>{
const getNews = async() =>{
const newsData = await httpClient.get(`/feed/${pk}/?page=${page.toString()}`)
setNews(newsData.data);
const userData = await httpClient.get('/profile/')
setUser(userData)
}
getNews();
}, [page])
How can i get data in the first time render?
because you have [page] in the dependency array - add hook for initial render:
const [page, setPage] = useState(0);
useEffect(() => setPage(1), [])
You will always have your state what you initialize it as on first render, react won't wait until useEffect is finished before render since that would lock up the UI.
You need some sort of loading indicator while data is fetching, you can do this for example
const [loading, setLoading] = useState(true);
const [news, setNews] = useState({});
const [page, setPage] = useState(1);
const [user, setUser] = useState({});
useEffect(() =>{
const getNews = async() =>{
const newsData = await httpClient.get(`/feed/${pk}/?page=${page.toString()}`)
setNews(newsData.data);
const userData = await httpClient.get('/profile/')
setUser(userData)
setLoading(false)
}
setLoading(true)
getNews();
}, [page])
if (loading) {
return <>{"loading"}</>
}
change the return value to whatever you want, maybe you want to just return an empty <></> component so that when it first shows up it'll have all the data.
I have managed to push content and image and the name of the image is also added to the database as a reference, and I have managed to retrieve only content. if anyone can help me out it will be great.
As you can see my Home.js code below
Home.js :
function Home(isAuth) {
const [postList, setPostList] = useState([]);
const [imageUrl, setImageUrl] = useState(undefined);
const postsCollectionRef = collection(db, "posts");
useEffect(() => {
const getPosts = async () => {
const data = await getDocs(postsCollectionRef);
setPostList(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
};
const getImage = async () => {
const storage = getStorage()
.ref('/' + `${post.cover}`) //name in storage in firebase console
.getDownloadURL()
.then((url) => {
setImageUrl(url);
})
}
getPosts();
})
}
I am trying to execute a function to update a setState but it as well needs other state to load first.
const [chatsIds, setChatsIds] = useState([]);
const [chats, setChats] = useState([]);
useEffect(() => {
getChatsIds();
}, []);
useEffect(() => {
getChats();
}, [chats]);
the "getChats" needs the value from "chatsIds" but when the screen is loaded the value isn't , only when i reload the app again it gets the value.
Here are the functions :
const getChatsIds = async () => {
const ids = await getDoc(userRef, "chats");
setChatsIds(ids);
}
const getChats = async () => {
const chatsArr = [];
chatsIds.forEach(async (id) => {
const chat = await getDoc(doc(db, "Chats", id));
chatsArr.push(chat);
console.log(chatsArr);
});
setChats(chatsArr);
}
I've tried with the useEffect and useLayoutEffect hooks, with promises and async functions, but i haven't found what i'm doing wrong :(
The problem is in your useEffect hook dependency. It should depends on chatsIds not chats.
useEffect(() => {
getChats();
}, [chatsIds]);
Which mean fetching chatsIds should depend on first mount and fetching chats should depend on if chatsIds is chnaged.
You simply change the useEffect hook to like below.
useEffect(() => {
getChatsIds();
}, [chatsIds]);
I Think getChat() is depend on chatIds...
so you use useEffect with chatIds on dependency
const [chatsIds, setChatsIds] = useState([]);
const [chats, setChats] = useState([]);
useEffect(() => {
getChatsIds();
}, []);
useEffect(() => {
getChats(chatsIds);
}, [chatsIds]);
const getChatsIds = async () => {
const ids = await getDoc(userRef, "chats");
setChatsIds(ids);
}
const getChats = async (chatsIds) => {
const chatsArr = [];
chatsIds.forEach(async (id) => {
const chat = await getDoc(doc(db, "Chats", id));
chatsArr.push(chat);
console.log(chatsArr);
});
setChats(chatsArr);
}
[This is the document structure][1] I need to get data from nested collection (journal/userID/entries) in Firestore into a Flatlist (React Native/Expo). Here is my code snippet:
function TextEntry() {
const ref =
firebase
.firestore()
.collection('journal')
.doc(currentUserUID)
.collection('entry')
useEffect(() => {
return ref.onSnapshot(querySnapshot => {
const list = [];
console.log(currentUserUID)
querySnapshot.forEach(doc => {
const { title } = doc.data()
list.push({
id: doc.id,
title,
});
});
setTodos(list);
if (loading) {
setLoading(false);
}
});
}, []);
const [todo, setTodo] = useState('');
const [loading, setLoading] = useState(true);
const [todos, setTodos] = useState([]);
let currentUserUID = firebase.auth().currentUser.uid;
async function addTodo() {
await ref.add({
title: todo,
});
setTodo('');
}
So I'm using useEffect hook to fetch my data from database and after I get that data I want to set it as useState for title and postBody, but it doesn't work, because useEffect hook runs "last", how can I fix it?
Code:
const [cPost, setCPost] = useState([]);
const postId = id.match.params.id;
useEffect(() => {
axios.get('http://localhost:5000/posts/'+postId)
.then(posts => {
setCPost(posts.data);
console.log("SAS");
})
}, []);
const [title, setTitle] = useState(cPost.title);
const [postBody, setPostBody] = useState(cPost.postBody);
As a temporary and quick solution, you can use such workaround:
const [cPost, setCPost] = useState();
const [title, setTitle] = useState();
const [postBody, setPostBody] = useState();
const postId = id.match.params.id;
useEffect(() => {
axios.get('http://localhost:5000/posts/'+postId)
.then(post => {
setCPost(post.data);
console.log("SAS");
})
}, []);
useEffect(() => {
if(cPost) {
setTitle(cPost.title);
setPostBody(cPost.postBody);
}
}, [cPost]);
Or the second option:
const [cPost, setCPost] = useState();
const [title, setTitle] = useState();
const [postBody, setPostBody] = useState();
const postId = id.match.params.id;
useEffect(() => {
axios.get('http://localhost:5000/posts/'+postId)
.then(post => {
setCPost(post.data);
setTitle(post.title);
setPostBody(post.postBody);
console.log("SAS");
})
}, []);
But in the future I would recommend doing side effects like API requests and others using special libraries or create hook for making API requests.
For example redux-saga or redux-thunk.
And use a state manager like redux or mobx.
P.S. and consider whether you need to store the title and body separately in the component state. I have a strong suspicion that you have no need for it.