Shopify JS Buy SDK刷新时读取collections[5].products报错求助
问题:Shopify Buy SDK 获取集合产品时刷新报错
我正在用Shopify Buy SDK渲染集合中的产品,控制台能正常打印collections[5],展开后也能看到其products属性对应的GraphModel,但刷新页面时会抛出错误:cannot read properties of undefined (reading 'products')。
可正常运行的代码
const Home = () => { const { fetchAllProducts, fetchAllCollections, products, collections } = useContext(ShopContext); useEffect(() => { fetchAllCollections(); }, [fetchAllCollections]); console.log(collections[5]); }
刷新时报错的代码
const Home = () => { const { fetchAllProducts, fetchAllCollections, products, collections } = useContext(ShopContext); useEffect(() => { fetchAllCollections(); }, [fetchAllCollections]); console.log(collections[5].products); }
ShopContext 代码
import React, { Component } from "react"; import Client from "shopify-buy"; const ShopContext = React.createContext(); const client = Client.buildClient({ domain: process.env.REACT_APP_SHOPIFY_DOMAIN, storefrontAccessToken: process.env.REACT_APP_SHOPIFY_API, }); export class shopProvider extends Component { state = { collection: {}, collections: [], product: {}, products: [], checkout: {}, isCartOpen: false, isMenuOpen: false, }; componentDidMount() { if (localStorage.checkout_id) { this.fetchCheckout(localStorage.checkout_id); } else { this.createCheckout(); } } createCheckout = async () => { const checkout = await client.checkout.create(); localStorage.setItem("checkout_id", checkout.id); this.setState({ checkout: checkout }); }; fetchCheckout = (checkoutId) => { client.checkout.fetch(checkoutId).then((checkout) => { this.setState({ checkout: checkout }); }); }; addItemToCheckout = async (variantId, quantity) => { const lineItemsToAdd = [{ variantId, quantity: parseInt(quantity, 10) }]; const checkout = await client.checkout.addLineItems( this.state.checkout.id, lineItemsToAdd ); this.setState({ checkout: checkout }); this.openCart(); }; removeLineItem = async (lineItemIdsToRemove) => { const checkout = await client.checkout.removeLineItems( this.state.checkout.id, lineItemIdsToRemove ); this.setState({ checkout: checkout }); }; fetchAllCollections = async () => { const collections = await client.collection.fetchAllWithProducts(); this.setState({ collections: collections }); } fetchAllProducts = async () => { const products = await client.product.fetchAll(); this.setState({ products: products }); }; fetchProductWithHandle = async (handle) => { const product = await client.product.fetchByHandle(handle); this.setState({ product: product }); }; closeCart = () => { this.setState({ isCartOpen: false }); }; openCart = () => { this.setState({ isCartOpen: true }); }; render() { return ( <ShopContext.Provider value={{ ...this.state, fetchAllProducts: this.fetchAllProducts, fetchProductWithHandle: this.fetchProductWithHandle, addItemToCheckout: this.addItemToCheckout, removeLineItem: this.removeLineItem, closeCart: this.closeCart, openCart: this.openCart, closeMenu: this.closeMenu, openMenu: this.openMenu, fetchAllCollections: this.fetchAllCollections, }} > {this.props.children} </ShopContext.Provider> ); } } const ShopConsumer = ShopContext.Consumer; export { ShopConsumer, ShopContext }; export default shopProvider;
原因与解决办法
核心原因
页面初始化时,collections是初始状态的空数组,此时collections[5]为undefined,直接访问undefined.products必然报错。控制台能正常显示collections[5]是因为浏览器会异步更新控制台内容——当API请求完成、collections状态更新后,控制台会展示最新值,但代码执行时还是初始的空数组状态。
解决办法
1. 使用可选链操作符安全访问
用?.语法避免访问undefined的属性:
console.log(collections[5]?.products);
2. 监听状态变化,条件执行
通过useEffect监听collections的变化,确保数据加载完成后再访问:
useEffect(() => { // 确保集合数量足够,再访问第6个元素(下标5) if (collections.length > 5) { console.log(collections[5].products); } }, [collections]);
3. 添加加载状态判断
在shopProvider的state中新增加载状态,组件中判断加载完成后再执行逻辑:
- 在
shopProvider的state里添加isLoading: true - 更新
fetchAllCollections方法:
fetchAllCollections = async () => { const collections = await client.collection.fetchAllWithProducts(); this.setState({ collections: collections, isLoading: false }); }
- 在Home组件中处理加载状态:
const Home = () => { const { fetchAllCollections, collections, isLoading } = useContext(ShopContext); useEffect(() => { fetchAllCollections(); }, [fetchAllCollections]); // 加载中时展示占位内容 if (isLoading) return <div>加载中...</div>; console.log(collections[5].products); // 后续渲染逻辑 }
内容的提问来源于stack exchange,提问作者Noah Bruce
相关产品推荐
相关产品推荐

