Reputation: 315
I am currently trying to load my product data into redux, but so far I cant seem to pass the product information returned from firestore into the reducer.
Index.js -> load first 10 products from firestore soon after store was created.
store.dispatch(getAllProducts)
action/index.js
import shop from '../api/shop'
const receiveProducts = products => ({
type: types.RECEIVE_PRODUCTS
products
})
const getAllProducts = () => dispatch => {
shop.getProducts(products => {
dispatch(receiveProducts)
})
}
shop.js
import fetchProducts from './firebase/fetchProducts'
export default {
getProducts: (cb) => cb(fetchProducts())
}
fetchProducts.js
const fetchProducts = async() => {
const ProductList = await firebase_product.firestore()
.collection('store_products').limit(10)
ProductList.get().then((querySnapshot) => {
const tempDoc = querySnapshot.docs.map((doc) => {
return { id: doc.id, ...doc.data() }
})
}).catch(function (error) {
console.log('Error getting Documents: ', error)
})
}
In product reducers
const byId = (state={}, action) => {
case RECEIVE_PRODUCTS:
console.log(action); <- this should be products, but it is now promise due to aysnc function return?
}
I can get the documents with no issues (tempDocs gets the first 10 documents without any issue.) but I am not able to pass the data back into my redux. If I were creating normal react app, I would add a loading state when retrieving the documents from firestore, do I need to do something similar in redux as well ?
Sorry if the code seems messy at the moment.
Upvotes: 0
Views: 123
Reputation: 3499
A generalized routine I use to accomplish exactly this:
const ListenGenerator = (sliceName, tableName, filterArray) => {
return () => {
//returns a listener function
try {
const unsubscribe = ListenCollectionGroupQuery(
tableName,
filterArray,
(listenResults) => {
store.dispatch(
genericReduxAction(sliceName, tableName, listenResults)
);
},
(err) => {
console.log(
err + ` ListenGenerator listener ${sliceName} ${tableName} err`
);
}
);
//The unsubscribe function to be returned includes clearing
// Redux entry
const unsubscriber = () => {
//effectively a closure
unsubscribe();
store.dispatch(genericReduxAction(sliceName, tableName, null));
};
return unsubscriber;
} catch (err) {
console.log(
`failed:ListenGenerator ${sliceName} ${tableName} err: ${err}`
);
}
};
};
The ListenCollectionGroupQuery
does what it sounds like; it takes a tableName
, an array of filter/.where() conditions, and data/err callbacks.
The genericReduxAction
pretty much just concatenates the sliceName and TableName to create an action type (my reducers de-construct action types similarly). The point is you can put the dispatch into the datacallback.
Beyond this, you simply treat Redux as Redux - subscribe, get, etc just as if the data were completely local.
Upvotes: 1
Reputation: 1336
fetchProducts
is an async function so you need to wait for its result before calling dispatch
. There are a few ways you could do this, you could give fetchProducts
access to dispatch
via a hook or passing dispatch to fetchProducts
directly.
I don't quite understand the purpose of shop.js
but you also could await
fetchProducts
and then pass the result of that into dispatch.
Upvotes: 2