React组件直接打开URL时useEffect未触发,无法获取商品数据导致TypeError报错
React组件直接打开URL时useEffect未触发,无法获取商品数据导致TypeError报错
兄弟,我来帮你捋清楚问题出在哪:
核心原因:组件渲染时直接抛出TypeError,中断了所有后续代码执行
你看到console.log("fetch article data")没打印,是因为组件在执行到selectedColor的初始化语句时就崩溃了,后面的useEffect根本没机会运行!
当你直接打开URL时,location.state是空的,所以article是undefined,你把它赋值给Article状态的初始值,也就是const [Article,setArticle] = useState(article);,此时Article也是undefined。
接下来执行这行代码:
const [selectedColor, setSelectedColor] = useState(Object.keys(Article.colors)[0]);
这里直接访问undefined.colors,瞬间抛出Cannot read properties of undefined (reading 'colors')的TypeError,组件渲染失败,后面的useEffect、console.log全被中断,自然看不到"fetch article data"的打印。
解决步骤:先修复渲染报错,再优化数据加载逻辑
1. 先堵上渲染崩溃的漏洞
给Article状态和所有依赖它的变量加默认值,避免访问undefined的属性:
// 初始值设为空对象,避免undefined const [Article,setArticle] = useState(article || {}); // 给selectedColor加可选链和默认值,用函数式初始值更稳妥 const [selectedColor, setSelectedColor] = useState(() => { return Article?.colors ? Object.keys(Article.colors)[0] : ""; }); // selectedSize同样处理 const [selectedSize, setSelectedSize] = useState(Article?.sizes?.[0] || ""); // 解构article数据时也加默认值 const { colors = {}, images = {}, sizes = [] } = Article;
2. 优化useEffect的执行逻辑
现在组件不会崩溃了,useEffect就能正常触发。可以调整依赖和判断条件,确保在需要时正确拉取数据:
// 新增加载状态,提升用户体验 const [isLoading, setIsLoading] = useState(!article); useEffect(() => { const fetchArticleData = async () => { console.log("fetch article data"); // 只有当没有路由传过来的article,且有id时才去拉取 if (!article && id) { try { setIsLoading(true); const docRef = doc(db, "Articles", id); const docSnap = await getDoc(docRef); if (docSnap.exists()) { setArticle(docSnap.data()); } } catch (err) { console.error("拉取商品数据失败:", err); } finally { setIsLoading(false); } } else if (article) { setArticle(article); setIsLoading(false); } }; fetchArticleData(); }, [article, id]);
3. 给用户加加载反馈
在组件return的最前面,加个加载判断,避免用户看到空白或异常内容:
if (isLoading && Object.keys(Article).length === 0) { return <Spinner label="加载商品中..." />; // 用你项目里的加载组件 } // 如果加载完还是没有商品数据,显示错误提示 if (!isLoading && Object.keys(Article).length === 0) { return <div className="text-center mt-10">该商品不存在或已下架</div>; }
额外优化建议
- 给
location.state的解构加更明确的默认值:const { article } = location.state || { article: null }; - 可以把
Article状态的命名改成小写article,避免和组件名Article冲突(虽然JS区分大小写,但容易混淆) - 错误捕获里可以加个提示,方便你排查问题,比如
console.error("拉取失败:", err)
这样修改后,直接打开URL时,组件不会崩溃,useEffect会正常触发去拉取Firestore的数据,你就能看到"fetch article data"的打印了。
备注:内容来源于stack exchange,提问作者Muhammad Ahmed
相关产品推荐
相关产品推荐

