because my return is [{"singles": [[Object], [Object]]}] - firebase

I am using a useEffect to get information from a collection and a sub-collection, however, the data return from my sub-collection is being [{"singles": [[Object], [Object]]}]
useEffect(() => {
fireStore
.collection('users')
// .where('category','==','band')
// .where('status','==','approved')
.where('email','==','marcelomenoli12#gmail.com')
.get()
.then( async (musics) => {
const allSingles = musics.docs.map(async (single) => {
const items = await single.ref.collection('musics').get();
return {
// cover: single.data().cover,
// name: single.data().bandArtistName,
singles: items.docs.map((item) => ({
id: item.id,
...item.data(),
}))
}
});
const filteredSingles = await Promise.all(allSingles);
setDATA(filteredSingles);
});
}, []);
console.log(DATA);

You should use more than one then clauses, so every async operation return values. Otherwise inner await responses are not come on time.
I tried to update your code. I hope that helps.
useEffect(() => {
fireStore
.collection('users')
.where('email','==','marcelomenoli12#gmail.com')
.get()
.then( async (musics) => {
const allSingles = musics.docs.map(async (single) => {
return await single.ref.collection('musics').get();
})
.then((items)=>{
// cover: single.data().cover,
// name: single.data().bandArtistName,
singles: items.docs.map((item) => ({
id: item.id,
...item.data(),
}))
})
}, []);
console.log(DATA);

Related

RTK startListening will accumulate the effects?

For example:
export const authMiddleWare = createListenerMiddleware<TRootState>();
const startAuthMiddleWare = authMiddleWare.startListening as TListener;
startAuthMiddleWare({
actionCreator: actionSetToken,
effect: (_, {dispatch, getState}) => {
favoriteProductsLoggedInEffect(dispatch, getState);
cartLoggedInEffect(dispatch, getState);
},
});
startAuthMiddleWare({
actionCreator: actionFlushToken,
effect: () => {
AuthService.flushTokens();
},
});
First I'm subscribe to actionSetToken and after that I've subscribe to actionFlushToken trough single startAuthMiddleWare method. Is it safe? Can I override the actionSetToken-subscrib by subscribing to actionSetFlushToken?

How to get multiple references in a firestore snapshot

I have a firestore collection containing post documents, each document contains a reference to an author (user) and a case document.
How do I get the user and the case in the same onSnapshot?
Here's what I'd like to do with await, but that doesn't seem to be an option with react-native-firebase.
export const firebasePostLooper = (snapshot) => {
let data = [];
snapshot.forEach(async (doc) => {
let newItem = {id: doc.id, ...doc.data()};
if (newItem.author) {
let authorData = await getDoc(newItem.author); // doesn't work with rnfirebase
if (authorData.exists()) {
newItem.userData = {userID: authorData.id, ...authorData.data()};
}
}
if (newItem.case) {
let caseData = await getDoc(newItem.case);
if (caseData.exists()) {
newItem.userData = {userID: caseData.id, ...caseData.data()};
}
}
data.push(newItem);
});
return data;
};
This doesn't work because getDoc() doesn't exist.
So I'm left with using .then()
export const firebasePostLooper = (snapshot) => {
let data = [];
snapshot.forEach((doc) => {
let newItem = {id: doc.id, ...doc.data()};
if (newItem.author) {
newItem.author
.get()
.then((res) => {
newItem.authorData = res.data();
if (newItem.case) {
newItem.case
.get()
.then((caseRes) => {
newItem.caseData = caseRes.data();
data.push(newItem);
})
.catch((err) => console.error(err));
}
})
.catch((err) => console.error(err));
} else {
data.push(newItem);
}
});
return data;
};
This second method doesn't seem to be working, data is empty at the return statement but data.push(newItem) contains the correct document with the 2 referenced documents.
You're returning data before it gets filled inside the promise. You should handle the returning of the data inside a .then() in order to return it after the promise has resolved and not before.
Take a look at this example where if we handle the emptyData object outside the promise chain, we just return the initial value before it has been filled.
let promise = new Promise((resolve, reject)=>{
setTimeout(resolve, 1000, 'foo');
})
let emptyData= [];
let notEmptyData = [];
promise
.then(res=>{
emptyData.push(res);
notEmptyData.push(res);
console.log("Full data: " + notEmptyData) // "Full data: foo"
});
console.log("Empty data: " + emptyData); // "Empty data: "

Cannot fix Promise in react native Promise { "_U": 0, "_V": 0, "_W": null, "_X": null, }

Why did I add Promise to the function it still gives an error ??
I cannot call this function again with the parameter I give ??
Get User by Uid in Fire.js file( I custom this file )
getUserbyUid = async ({ Uid }) => {
return new Promise((res, rej) => {
firebase.firestore()
.collection('user')
.doc(Uid)
.get()
.then(documentSnapshot => {
res(documentSnapshot.data().name);
})
.catch(error => { rej(error) });
})
}
in Feed.js i call it
async componentDidMount() {
await firebase.firestore().collection("Post").get()
.then(querySnapshot => {
querySnapshot.forEach(documentSnapshot => {
this.setState({ dataPost: this.state.dataPost.concat({ ...documentSnapshot.data(),
key: documentSnapshot.id, }) })
console.log(Fire.shared.getUserbyUid(documentSnapshot.data().uid)); <= error this if i console.log(documentSnapshot.data().uid)) it will return a Uid
but If i call in above it will return Promise { "_U": 0,"_V": 0, "_W": null,"_X": null,}
});
});
}

How to read array of objects with data from fireabse

I have a function that create tasks and writing it in firebase real time database.
export const createNewTask = (task) => new Promise(async (resolve, reject) => {
try {
await database().ref('tasks').child(auth().currentUser.uid).child(task.taskCreationDate.toString()).set(task);
resolve();
} catch (e) {
reject(e);
}
});
And it's working good :
Now, I have a socond functions that should read that tasks.
export const fetchTasks = () => (dispatch) => new Promise(async (resolve, reject) => {
try {
const snapshot = await database().ref('tasks').child(auth().currentUser.uid).once('value');
if (snapshot.exists) {
const tasks = snapshot.val();
dispatch({
type: FETCH_TASKS,
payload: tasks,
});
resolve(tasks);
} else {
resolve(snapshot);
}
} catch (e) {
reject(e);
}
});
And here is the problem:
When I'm using useSelector in my home screen const tasks = useSelector(state => state.GeneralReducer.taskList);
The tasks list is undefiend.
When I used mock data with same objects , it's work fine.
How can I get a list of task?
Ok , fixed it by adding :
Object.keys(data).map(key => ({...data[key], id: key}));
to the function fetchTasks.
export const fetchTasks = () => (dispatch) => new Promise(async (resolve, reject) => {
try {
const snapshot = await database().ref('tasks').child(auth().currentUser.uid).once('value');
if (snapshot.exists) {
const data = snapshot.val();
const tasks = Object.keys(data).map(key => ({...data[key], id: key}));
dispatch({
type: FETCH_TASKS,
payload: tasks,
});
resolve(tasks);
} else {
resolve(snapshot);
}
} catch (e) {
reject(e);
}
});

How can i write data that is coming from Firebase to store quickly?

Firstly, I'm working with React Native. I'm getting a data from Firebase and want to write to store (by Redux) quickly. But It doesn't work. You can find my all of codes below:
Function:
async getTumData (uid) {
const {selectedGroupDetail, getSelectedGroupDetail} = this.props;
var yeniGrupDetayi = {};
await firebase.database().ref("/groups/"+uid).once('value').then(
function(snapshot){
yeniGrupDetayi = {...snapshot.val(), uid: uid};
}).catch(e => console.log(e.message));
console.log("FONKSIYON ICERISINDEKI ITEM ==>", yeniGrupDetayi);
this.props.getSelectedGroupDetail(yeniGrupDetayi);
console.log("ACTION'DAN GELEN ITEM ===>", selectedGroupDetail);
}
Action:
export const getSelectedGroupDetail = (yeniGrupDetayi) => {
return {
type: GET_SELECTED_GROUP_DETAIL,
payload: yeniGrupDetayi
}
};
Reducer:
case GET_SELECTED_GROUP_DETAIL:
return { ...state, selectedGroupDetail: action.payload}
Çıktı:
FONKSIYON ICERISINDEKI ITEM ==> {admin: {…}, groupDescription: "Yaygın inancın tersine, Lorem Ipsum rastgele sözcü…erini incelediğinde kesin bir kaynağa ulaşmıştır.", groupName: "İnsan Kaynakları", groupProfilePic: "", members: {…}, …}
ACTION'DAN GELEN ITEM ===> {}
There is a FlatList in my page and I defined a button in renderItem of FlatList. When i click to this button, getTumData() function is working.
When i click to this button first time, selectedGroupDetail is null. Second time, it shows previous data.
How can i write a data to Store quickly and fast?
Thanks,
The thing is:
- You're using both async/await, and then/catch in your code.
- you're calling getSelectedGroupDetail before your async code resolves.
Fast Solution
getTumData = (uid) => {
const {selectedGroupDetail, getSelectedGroupDetail} = this.props;
var yeniGrupDetayi = {};
firebase.database().ref("/groups/"+uid).once('value').then(
(snapshot) => {
yeniGrupDetayi = {...snapshot.val(), uid: uid};
this.props.getSelectedGroupDetail(yeniGrupDetayi);
}).catch(e => console.log(e.message));
};
Better Solution:
1st: use Redux-Thunk middleware.
2nd: Move your Async code into your action creator: I mean this
async getTumData (uid) {
const {selectedGroupDetail, getSelectedGroupDetail} = this.props;
var yeniGrupDetayi = {};
await firebase.database().ref("/groups/"+uid).once('value').then(
function(snapshot){
yeniGrupDetayi = {...snapshot.val(), uid: uid};
}).catch(e => console.log(e.message));
console.log("FONKSIYON ICERISINDEKI ITEM ==>", yeniGrupDetayi);
this.props.getSelectedGroupDetail(yeniGrupDetayi);
console.log("ACTION'DAN GELEN ITEM ===>", selectedGroupDetail);
}
3rd: Your reducer should have another piece of data as an indicator for the time-gap before your selectedGroupDetail resolves:
// reducer initial state:
const INITIAL_STATE = { error: '', loading: false, selectedGroupDetail: null }
4th: Inside your action creator, you should dispatch 3 actions:
ACTION_NAME_START // This should should only set loading to true in your reducer.
ACTION_NAME_SUCCESS // set loading to false, and selectedGroupDetail to the new collection retured
ACTION_NAME_FAIL // in case op failed set error
5th: Your React component, should display a loading indicator (spinner or somthing), and maybe disable FlatList button during the loading state.
// Action creator
export const myAction = () => (dispatch) => {
dispatch({ type: ACTION_NAME_START });
firebase.database().ref("/groups/"+uid).once('value').then(
function(snapshot){
yeniGrupDetayi = {...snapshot.val(), uid: uid};
dispatch({ type: ACTION_NAME_SUCCESS, payload: yeniGrupDetayi });
}).catch(e => {
dispatch({ type: ACTION_NAME_FAIL, payload: e.message });
});
};
// Reducer
const INITIAL_STATE = {
loading: false,
error: '',
data: null,
};
export default (state = INITIAL_STATE, { type, payload }) => {
switch (type) {
case ACTION_NAME_START:
return {
...state,
error: '',
loading: true,
data: null,
};
case ACTION_NAME_SUCCESS:
return {
...state,
error: '',
loading: false,
data: payload,
};
case ACTION_NAME_FAIL:
return {
...state,
error: payload,
loading: false,
data: null,
};
default:
return state;
}
};

Resources