Reputation: 428
Is there a way to use createAsyncThunk with Firebase listeners, for example firestore.collection.onSnapshot?
It may not work because the way onSnapshot works (it's a listener that receives data and fires a callback every time firestore updates and it returns a function that unsubscribes the listener). I tried implementing createAsyncThunk but couldn't figure it out.
Here's my current thunk implementation which does work:
const listenerUnsubscribeList = [];
export function fetchProjects() {
return dispatch => {
dispatch(fetchProjectsPending());
const unsubscribe = firestore
.collection('projects')
.onSnapshot(
snapshot => { dispatch(fetchProjectsFulfilled(snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })))) },
error => { dispatch(fetchProjectsError(error)) },
);
listenerUnsubscribeList.push(unsubscribe);
}
}
Here's my attempt at createAsyncThunk which does not work. I'm getting database/fetchProjects/pending
and database/fetchProjects/fulfilled
but payload is undefined
const listenerUnsubscribeList = [];
export const fetchProjects = createAsyncThunk(
'database/fetchProjects',
async (_, thunkAPI) => {
const unsubscribe = await firestore
.collection('projects')
.onSnapshot(
snapshot => { return snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })) },
error => { return error },
);
listenerUnsubscribeList.push(unsubscribe);
}
);
Upvotes: 6
Views: 2501
Reputation: 2558
I tried making it work with createAsyncThunk
but did not manage to solve it.
I dont know if my approach is the right one but I simply created a custom thunk
that handles re-firing any action as needed. I create a loading
/ fulfilled
/ error
action that will handle the data accordingly.
// Action.js
/*
listenToInboxInDb is a firebase listener that will re-fire with fresh data.
See how I am returning unsubscribe to be able to call unsubscribe
when my component unmounts
*/
export const getConnectionRequests = () => {
return (dispatch) => {
dispatch(fetchConnectionsRequestsLoading())
const unsubscribe = listenToInboxInDb(([data, error]) => {
if (data) {
dispatch(fetchConnectionsRequestFullfilled(data))
}
if (error) {
dispatch(fetchConnectionsRequestRejected(error))
}
})
return unsubscribe
}
}
// Reducer.js
const connectionsSlice = createSlice({
name: "connections",
initialState: INITIAL_STATE,
reducers: {
// ...other reducers
fetchConnectionsRequestsLoading(state) {
state.connectionRequestsStatus = REQUEST_STATUS.loading
},
fetchConnectionsRequestFullfilled(state, action) {
state.error = null
state.data.connectionRequests = action.payload
state.connectionRequestsStatus = REQUEST_STATUS.succeeded
},
fetchConnectionsRequestRejected(state, action) {
state.error = action.error
state.connectionRequestsStatus = REQUEST_STATUS.failed
},
},
})
Upvotes: 1