re-render the component when retrieving data - javascript

When i fetch data from firebase the request still running and the data is still running in the console i don't know why it didn't stop
i used cleanup function, abort controller but it didn't work
here is my code
i hope you can help me
const [fetchedPhoto, setFetchedPhoto]= useState({
imagUrl:[]
})
const retrieveImg= useCallback(async() => {
try{
const url=[]
const data= await fetch('https://naif-65aa6.firebaseio.com/test-project.json',{signal:controller.signal})
const response= await data.json()
for(const key in response){
url.push({
id: key,
name: response[key].name,
phone: response[key].phone
})
}
setFetchedPhoto(prevState=>({
...prevState,
imagUrl: prevState.imagUrl.concat(url)
}))
console.log(fetchedPhoto.imagUrl);
} catch(err) {
console.log(err);
}
},[fetchedPhoto])
useEffect(()=>{
retrieveImg()
return()=>controller.abort()
},[fetchedPhoto])

Related

how to efficiently retrieve data from firebase/Firestore subcollection?

I'm using firestore to store posts each post could have simple properties such as {title: 'hi', comment: true} I'm able to easily fetch the user's specific posts since my collection structure looks like this: posts/user.id/post/post.name so an example will be posts/1234sofa/post/cool day
with this way of structuring, I'm able to easily fetch data for the user, but I'm having trouble with two things how do I fetch and display all posts for my main feed, and what's the most effective way of doing this? here is my current function for fetching user-specific data:
const submitpost = async () => {
try {
const collectionRef=collection(db,`posts`,user.uid.toString(),'post')
await addDoc(collectionRef, {
post: post,
timestamp: serverTimestamp(),
canComment: switchValue,
user: user.uid,
avatar: user.photoURL,
username: user.displayName,
});
toast({ title: "posted", status: "success", duration: 2000 });
} catch (error) {
console.log(error);
}
};
this specific function creates a structure like this in firebase posts are just takes and take is singular post respectively I just changed the name so its easier to understand:
now here is how im fetching the data for my spefic user:
const [user] = useAuthState(auth);
const [takes, settakes] = useState([]);
const getData = async () => {
// if user is present run function
if (user) {
// const docRef = doc(db, "users", user.uid);
// const collectionRef = collection(docRef, "takes");
// const querySnapshot = await getDocs(collectionRef);
try {
const docRef = doc(db, "posts", user.uid);
const collectionRef = collection(db,'posts',user.uid,'takes');
const querySnapshot = await getDocs(collectionRef);
const data = querySnapshot.docs.map((d) => ({
id: d.id,
...d.data(),
}));
settakes(data);
} catch (error) {
console.log(error);
}
//
}
};
here is the function that doesn't work when fetching all data for main feed:
const [user]=useAuthState(auth)
const [allfeed, setallfeed] = useState([])
const getData = async () => {
if(user){
const collectionRef = collection(db, "posts");
const querySnapshot = await getDocs(collectionRef);
const data = querySnapshot.docs.map((d) => ({
id: d.id,
...d.data(),
}));
// get data from firebase
setallfeed(data)
}
}
useEffect(() => {
getData()
console.log('ran');
console.log(allfeed);
// rerun when user is present
}, [user]);
when I console log the allfeed it returns an empty array so my main problem is how to do I get all the data from the posts collection meaning posts/userid/post/post.title I need to get these for every user. and secondly is there a more efficient way to structure my data?
I would suggest using the onSnapshot() method if you want realtime updates from a collection or a specific document.
setState() does not make changes directly to the state object. It just creates queues for React core to update the state object of a React component. If you add the state to the useEffect, it compares the two objects, and since they have a different reference, it once again fetches the items and sets the new items object to the state. The state updates then triggers a re-render in the component. And on, and on, and on...
If you just want to log your data into your console then you must use a temporary variable rather than using setState:
const getData = async () => {
if(user){
// Using `getDocs`
const collectionRef = collection(db, "posts");
const querySnapshot = await getDocs(collectionRef);
const data = querySnapshot.docs.map((d) => ({
id: d.id,
...d.data(),
}));
console.log(data)
// ============================================= //
// Using `onSnapshot()`
const q = query(collection(db, "posts"));
const unsubscribe = onSnapshot(q, (querySnapshot) => {
const data = querySnapshot.docs.map(d => ({
id: d.id,
...d.data()
}))
console.log(data)
});
}
}
useEffect(() => {
getData();
}, []);
You could also use multiple useEffect() to get the updated state of the object:
const getData = async () => {
if(user){
// Using `getDocs`
const collectionRef = collection(db, "posts");
const querySnapshot = await getDocs(collectionRef);
const data = querySnapshot.docs.map((d) => ({
id: d.id,
...d.data(),
}));
setallfeed(data)
// ============================================= //
// Using `onSnapshot()`
const q = query(collection(db, "posts"));
const unsubscribe = onSnapshot(q, (querySnapshot) => {
const data = querySnapshot.docs.map(d => ({
id: d.id,
...d.data()
}))
setallfeed(data)
});
}
}
useEffect(() => {
getData();
}, [])
useEffect(() => {
console.log(allfeed);
}, [allfeed]);
If you want to render it to the component then you should call the state in the component and map the data into it. Take a look at the sample code below:
const getData = async () => {
if(user){
// Using `getDocs`
const collectionRef = collection(db, "posts");
const querySnapshot = await getDocs(collectionRef);
const data = querySnapshot.docs.map((d) => ({
id: d.id,
...d.data(),
}));
setallfeed(data)
// ============================================= //
// Using `onSnapshot()`
const q = query(collection(db, "posts"));
const unsubscribe = onSnapshot(q, (querySnapshot) => {
const data = querySnapshot.docs.map(d => ({
id: d.id,
...d.data()
}))
setallfeed(data)
});
}
}
useEffect(() => {
getData()
}, []);
return (
<div>
<p>SomeData: <p/>
{items.map((item) => (
<p key={item.id}>{item.fieldname}</p>
))}
</div>
);
For more information you may checkout these documentations:
Get data with Cloud Firestore
Get realtime updates with Cloud Firestore

Put results of a Get request from axios to an array

I don't understand a very simple task, I made a request from a API with axios in react.
If I console log the res.data, is like 170 result of single objects on my console.
I need to convert all these result in a single array of objects.
It's a basic task but I don't understand how to do it.
The application is a Trello Clone.
I have a variable called board that has all the data and with this list request, I grab all the column the the trello and append to ListObjects [] in newBoardData (it's a clone of board)
Here is my code:
//Get Request
const getList = async (id) => {
try {
return await axios.get(`${ENDPOINT}/lists/${id}`);
} catch (err) {
console.log(err);
}
};
const [loading, setLoading] = useState(false);
// Use Effect for grab the data with the listId
useEffect(() => {
(async () => {
setLoading(true);
const res = await (getList(listId));
//Loading up the listObjects
const oldList = board.board.listObjects
const newList = []
const payload = res.data;
//Adding all the old values to the new list (except for the current payload id)
for(let obj of oldList){
if(obj._id !== payload._id) newList.push(obj)
}
//Adding the current payload id
newList.push(payload)
const data = {
...board,
board: {...board.board, listObjects: newList}
};
setList(res.data);
// Here I put the data objects with the new ListObjects Array
setBoardNew(data);
setLoading(false);
})();
}, []);
Here is the console log of the get request res.data:
console.log of res.data
here is the board object:
board object
You can saw that there is a spam of result with the current res.data in ListObjects
I'think it make a request for every card in every list.
thank you very much!
UPDATE:
I will explain how the app works:
I have a file called Board.js, where I make this call (in the console log I have two call if I have two columns):
try {
return await axios.get(`${ENDPOINT}/boards/${id}`);
} catch (err) {
console.log(err);
}
};
useEffect(() => {
(async () => {
setLoading(true);
const res = await (getUserBoard(match.params.id));
if (res) {
axios.defaults.headers.common['boardId'] = match.params.id;
} else {
delete axios.defaults.headers.common['boardId'];
}
const payload = { ...res.data, listObjects: [], cardObjects: [] };
const data = {
...state,
board: { ...state.board, ...payload },
};
setBoardData(data);
setLoading(false);
})();
}, []);
Then I send the props data to the file List.js
{board.board.lists.map((listId, index) => (
<List key={listId} listId={listId} index={index} board={board} />
The list file send the data to
card.js
{list.cards.map((cardId, index) => (
<Card key={cardId} cardId={cardId} list={list} index={index} board={boardNew} />
The logic is: There is the board(board.js), in the board there are the lists (column)(list.js) in the lists there are the cards (card.js)
I hope it's more clear.
simple use this approach to add your new id value into the array state.
this.setState({ myArray: [...this.state.myArray, 'new value'] }) //simple value
this.setState({ myArray: [...this.state.myArray, ...[1,2,3] ] }) //another array

Not able to push my data in an json server

This is a local JSON server you can see on this URL
http://localhost:3003/CourseList/1
My hooks
const [subjectName,setsubjectName]=useState(
{
id: "",
subjectname: "Aptitude",
chapter: [
{
chapter1: "",
topic: [
{
topic1: ""
}
]
}
]
}
);
function when I click on add button which will check if it matches the id of a prop then it will perform the task
const addSubject = async id => {
console.log("id "+id);
axios.get(`http://localhost:3003/CourseList/`)
.then((res)=>{
res.data.map((list,index)=>{
if(list.id===props.id){
console.log(list.subject)
list.subject.push(subjectName);
}
})
})
.catch((error)=>{
console.log(error);
})
};
How can I push new data in the subject array? I am getting nothing
Here's the solution
const addSubject = async id => {
console.log("id "+id);
try{
const {data} = await axios.get("http://localhost:3003/CourseList")
data.map(async(item)=>{
if(item.id===id){
console.log(item);
item.subject.push(subjectName);
await axios.put(`http://localhost:3003/CourseList/${id}`,item)
}
})
const check= await axios.get(http://localhost:3003/CourseList/${id})
console.log(check)
}catch(err){
console.log(err.message)
}
};
If you're using a JSON-server it should have a default endpoint for PATH/PUT your new object. You need to send the Content/Type: application/json in your request header and set the jsonServer.bodyParser in your server.

How to pre-fetch data using prefetchQuery with React-Query

I am trying to pre-fetch data using react-query prefetchQuery. When I am inspecting browser DevTools network tab I can see that data that was requested for prefetchQuery is coming from the back-end but for some reason when I look into react-query DevTools it does generate the key in the cache but for some reason the Data is not there. Let me know what I am doing wrong.
import { useState, useEffect } from 'react';
import { useQuery, useQueryClient } from 'react-query';
import axios from 'axios';
const baseURL = process.env.api;
async function getSubCategoryListByCategoryId(id) {
// await new Promise((resolve) => setTimeout(resolve, 300));
console.log(`${baseURL}/category/subcategories/${id}`);
try {
const { data } = await axios.request({
baseURL,
url: `/category/subcategories/${id}`,
method: 'get',
});
console.log('data getSubCategoryListByCategoryId index: ', data);
return data;
} catch (error) {
console.log('getSubCategoryListByCategoryId error:', error);
}
}
// const initialState = {
// };
const ProductCreate = () => {
const [values, setValues] = useState(initialState);
const queryClient = useQueryClient();
const { data, isLoading, isError, error, isFetching } = useQuery(
'categoryList',
getPosts
);
const dataList = JSON.parse(data);
useEffect(() => {
setValues({ ...values, categories: dataList });
dataList.map((item) => {
console.log('useEffect values.categories item.id: ', item._id);
queryClient.prefetchQuery(
['subCategoryListByCategoryId', item._id],
getSubCategoryListByCategoryId(item._id)
);
});
}, []);
return <h1>Hello</h1>;
};
export default ProductCreate;
The second parameter to prefetchQuery expects a function that will fetch the data, similar to the queryFn passed to useQuery.
But here, you are invoking the function, thus passing the result of it into prefetchQuery:
getSubCategoryListByCategoryId(item._id)
if you want to do that, you can manually prime the query via queryClient.setQueryData, which accepts a key and the data for that key passed to it.
otherwise, the fix is probably just:
() => getSubCategoryListByCategoryId(item._id)

How to store ID of record in Firebase cloud functions

I'm saving data in the collection in the following way:
const userEntry= {
UserId: "I want documentID here",
UserName: "",
creationDate: ""
}
const churchResult = await saveChurchData(userEntry)
const saveData = async (data: object) => {
return database.collection('users').add(data)
.then(snapshot => {
return snapshot.get().then(doc => {
doc.data()
return doc.id
}).catch(err => {
console.log('Error getting documents', err);
return null;
});
}).catch(err => {
console.log('Error getting documents', err);
return null;
});
}
Is there any way that I store "documentID" of users table in the place of UserId. How can we do that in firebase cloud functions? I'm unable to find a way to store the documentID in the documentation.
I tried following, but it is giving wrong ID not docuemntID:
const key =firebase.database().ref().push()
Since I don't see any saveChurchData() method in your code, I make the assumption that instead of doing
const churchResult = await saveChurchData(userEntry)
you wan to do
const churchResult = await saveData(userEntry)
The following would do the trick, by using the doc() method without specifying any documentPath:
const userEntry = {
UserName: "",
creationDate: ""
}
const churchResult = await saveData(userEntry)
const saveData = async (data: object) => {
try {
const docRef = database.collection('users').doc();
const docId = docRef.id;
await docRef.set({ UserId: docId, ...data });
return docId;
} catch (error) {
//...
}
}

Categories

Resources