Firebase firestore:未处理的拒绝(RangeError):超出最大调用堆栈大小
Firebase firestore : Unhandled Rejection (RangeError): Maximum call stack size exceeded
出于学习目的开始使用 createAsyncThunk
,决定使用 firebase firestore 实现购物车,但我 运行 在我的 React 应用程序中尝试实现分页时遇到了问题。
我应该如何 return 在初始加载和后续加载(无限加载)期间将最后一个可见状态转换为我的 redux 状态
我基于 redux 教程沙箱中的代码:https://codesandbox.io/s/github/reduxjs/redux-essentials-example-app/tree/checkpoint-3-postRequests/?from-embed,但我没有连接到假 api,而是使用 firebase firestore。
从 firestore 获取产品的代码:ProductSlice.js
const InitialState = {
products : [],
status: 'idle',
error: null,
last: null, //to hold lastVisible when fetching data from firestore
}
export const fetchProducts = createAsyncThunk(types.RECEIVE_PRODUCTS, async (limit) => {
const resp = await fire_base_product.firestore()
.collection(collection_name).orderBy('id').limit(limit)
let result = resp.get().then((querySnapshot) => {
const lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1] //how set this to redux state
const products = querySnapshot.docs.map((doc)=> {
return { ...doc.data()}
})
return {
products: products,
lastVisible: lastVisible
};
})
return result;
}
我不太确定如何将此 lastVisible
数据设置回 redux 状态,是否可以参考?
#编辑:
尝试 return 产品列表和最后可见的数组,并在 createSlice 中分配 lastVisible,如下所述:
const productSlice = createSlice({
name:'products',
initialState:
reducers: {},
extraReducers:{
[fetchProducts.fulfilled]: (state, action) => {
state.products = state.products.concat(action.payload.products)
state.last = action.payload.lastVisible // this causes call stack error
}
}
});
使用上面的代码,如果我运行 react app,会报两个错误,
尝试将非序列化值分配给 redux 状态
firestore 中超出了最大调用堆栈大小
然后我尝试在创建配置期间添加中间件 serializableCheck,如下所示:
export default configureStore({
middlleware: getDefaultMiddlleWare({
serializableCheck: {
//ignore action type
ignoredActions : ['RECEIVE_PRODUCTS/fulfilled']
// ignore path
ignoredPath: ['products.last']
}
}),
... // reducer codes
})
即使现在我已经消除了第一个错误,超出的调用堆栈仍然存在。有谁知道为什么会这样?随意讨论是否有任何解决方法。谢谢。
编辑 2
类似的方法在使用 context 时有效,但在使用 redux 时无效。我是否需要按照 Firebase Unhandled error RangeError: Maximum call stack size exceeded 中的建议将 return 包装在 promise 中?
没能找到保存方法 lastVisible
,但我找到了一个解决方法,只需跟踪我的 firestore 数据的最后检索 ID,方法是将其保存到 redux 状态。
export const fetchProducts = createAsyncThunk(types.RECEIVE_PRODUCTS, async (limit) => {
const resp = await fire_base_product.firestore()
.collection(collection_name).orderBy('id').limit(limit)
let result = resp.get().then((querySnapshot) => {
var lastVisible = limit - 1; //only keep track of ID so we can avoid saving un-serialize coded
const products = querySnapshot.docs.map((doc)=> {
return { ...doc.data()}
})
return {
products: products,
lastVisible: lastVisible
};
})
return result;
}
在获取额外数据期间,我们可以使用 getState() 访问状态,如下所示:
export const fetchMoreProducts = createAsyncThunk(types.LOAD_MORE_PRODUCTS, async (limit, {getState}) => {
const last = getState().products.last
var newProducts = await firebase_product.firestore()
.collection('store_products').orderBy('id')
.startAfter(last).limit(limit)
const result = newProducts.get().then((querySnapshot) => {
var lastVisible = last + limit;
const products = querySnapshot.docs.map((doc) => {
return { ...doc.data() }
})
return {
products : products,
lastVisible: lastVisible
}
})
// return retrieved data from firebase
return result
})
但是这样做,我也可以一起跳过序列化检查配置。不确定这是否是正确的方法,但这就是我让分页工作的方式。如果有其他方法可以解决此问题,请随时告诉我。
如果你在 redux store 中存储不可序列化的对象,就会出现这个错误!
if you are getting some non-serializable data from firebase, serialize it before storing it in redux store!
const nonSerializable = firestore().collection().doc(uid).get().data();
// if using this nonSerializable object in reducer, serialized it using JSON.parse(JSON.stringify())
const serializable = JSON.parse(JSON.stringify(nonSerializable))
你应该像这样保存最后一个可见路径而不是整个数据
const lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1].ref.path
出于学习目的开始使用 createAsyncThunk
,决定使用 firebase firestore 实现购物车,但我 运行 在我的 React 应用程序中尝试实现分页时遇到了问题。
我应该如何 return 在初始加载和后续加载(无限加载)期间将最后一个可见状态转换为我的 redux 状态
我基于 redux 教程沙箱中的代码:https://codesandbox.io/s/github/reduxjs/redux-essentials-example-app/tree/checkpoint-3-postRequests/?from-embed,但我没有连接到假 api,而是使用 firebase firestore。
从 firestore 获取产品的代码:ProductSlice.js
const InitialState = {
products : [],
status: 'idle',
error: null,
last: null, //to hold lastVisible when fetching data from firestore
}
export const fetchProducts = createAsyncThunk(types.RECEIVE_PRODUCTS, async (limit) => {
const resp = await fire_base_product.firestore()
.collection(collection_name).orderBy('id').limit(limit)
let result = resp.get().then((querySnapshot) => {
const lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1] //how set this to redux state
const products = querySnapshot.docs.map((doc)=> {
return { ...doc.data()}
})
return {
products: products,
lastVisible: lastVisible
};
})
return result;
}
我不太确定如何将此 lastVisible
数据设置回 redux 状态,是否可以参考?
#编辑:
尝试 return 产品列表和最后可见的数组,并在 createSlice 中分配 lastVisible,如下所述:
const productSlice = createSlice({
name:'products',
initialState:
reducers: {},
extraReducers:{
[fetchProducts.fulfilled]: (state, action) => {
state.products = state.products.concat(action.payload.products)
state.last = action.payload.lastVisible // this causes call stack error
}
}
});
使用上面的代码,如果我运行 react app,会报两个错误,
尝试将非序列化值分配给 redux 状态
firestore 中超出了最大调用堆栈大小
然后我尝试在创建配置期间添加中间件 serializableCheck,如下所示:
export default configureStore({
middlleware: getDefaultMiddlleWare({
serializableCheck: {
//ignore action type
ignoredActions : ['RECEIVE_PRODUCTS/fulfilled']
// ignore path
ignoredPath: ['products.last']
}
}),
... // reducer codes
})
即使现在我已经消除了第一个错误,超出的调用堆栈仍然存在。有谁知道为什么会这样?随意讨论是否有任何解决方法。谢谢。
编辑 2
类似的方法在使用 context 时有效,但在使用 redux 时无效。我是否需要按照 Firebase Unhandled error RangeError: Maximum call stack size exceeded 中的建议将 return 包装在 promise 中?
没能找到保存方法 lastVisible
,但我找到了一个解决方法,只需跟踪我的 firestore 数据的最后检索 ID,方法是将其保存到 redux 状态。
export const fetchProducts = createAsyncThunk(types.RECEIVE_PRODUCTS, async (limit) => {
const resp = await fire_base_product.firestore()
.collection(collection_name).orderBy('id').limit(limit)
let result = resp.get().then((querySnapshot) => {
var lastVisible = limit - 1; //only keep track of ID so we can avoid saving un-serialize coded
const products = querySnapshot.docs.map((doc)=> {
return { ...doc.data()}
})
return {
products: products,
lastVisible: lastVisible
};
})
return result;
}
在获取额外数据期间,我们可以使用 getState() 访问状态,如下所示:
export const fetchMoreProducts = createAsyncThunk(types.LOAD_MORE_PRODUCTS, async (limit, {getState}) => {
const last = getState().products.last
var newProducts = await firebase_product.firestore()
.collection('store_products').orderBy('id')
.startAfter(last).limit(limit)
const result = newProducts.get().then((querySnapshot) => {
var lastVisible = last + limit;
const products = querySnapshot.docs.map((doc) => {
return { ...doc.data() }
})
return {
products : products,
lastVisible: lastVisible
}
})
// return retrieved data from firebase
return result
})
但是这样做,我也可以一起跳过序列化检查配置。不确定这是否是正确的方法,但这就是我让分页工作的方式。如果有其他方法可以解决此问题,请随时告诉我。
如果你在 redux store 中存储不可序列化的对象,就会出现这个错误!
if you are getting some non-serializable data from firebase, serialize it before storing it in redux store!
const nonSerializable = firestore().collection().doc(uid).get().data();
// if using this nonSerializable object in reducer, serialized it using JSON.parse(JSON.stringify())
const serializable = JSON.parse(JSON.stringify(nonSerializable))
你应该像这样保存最后一个可见路径而不是整个数据
const lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1].ref.path