React中useContext报错:page未定义,子菜单无法正常显示
React useContext 子菜单报错:page is undefined 解决方案
问题场景
使用React的useContext Hook开发Navbar和Submenu组件时,Navbar功能正常,但鼠标悬停Navbar触发子菜单时,Submenu组件抛出错误:Uncaught TypeError: _Context__WEBPACK_IMPORTED_MODULE_1__.useGlobalContext().page is undefined
报错原因分析
- Context初始状态缺失:全局Context的初始state未给
page设置默认结构,组件挂载时page为undefined,直接解构page: { page, links }触发报错。 - Navbar传参与数据不匹配:Navbar传递的page名称(如按钮文本"Product")与data.js中的page值(如"products")大小写不一致,导致无法匹配到对应数据,Context中的
page仍为undefined。 - Submenu未做边界处理:Submenu组件在渲染和useEffect钩子中直接使用
page和links,未处理它们为undefined的情况。
分步解决方案
1. 完善Context的初始状态与匹配逻辑
确保Context的state包含page的默认结构,并且在openSubmenu函数中正确匹配data.js的页面数据:
// Context.js import { createContext, useContext, useState } from 'react'; import sublinks from './data'; const GlobalContext = createContext(); export const GlobalProvider = ({ children }) => { const [isSubmenuOpen, setIsSubmenuOpen] = useState(false); // 初始化page为带默认值的对象,避免解构报错 const [page, setPage] = useState({ page: '', links: [] }); const [location, setLocation] = useState({ center: 0, bottom: 0 }); const openSubmenu = (pageName, coords) => { // 忽略大小写匹配data.js中的页面数据 const matchedPage = sublinks.find(item => item.page.toLowerCase() === pageName.toLowerCase()); // 找不到匹配项时设置默认空结构,避免后续报错 setPage(matchedPage || { page: '', links: [] }); setLocation(coords); setIsSubmenuOpen(true); }; const closeSubmenu = () => { setIsSubmenuOpen(false); }; return ( <GlobalContext.Provider value={{ isSubmenuOpen, page, location, openSubmenu, closeSubmenu }}> {children} </GlobalContext.Provider> ); }; export const useGlobalContext = () => useContext(GlobalContext);
2. 修复Navbar的传参匹配问题
调整Navbar中displaySubmenu函数的page处理逻辑(结合Context的兼容处理,这里无需额外修改,若需要严格匹配,可将按钮文本改为与data.js一致的名称,比如"Products"):
// Navbar.js const displaySubmenu = (e) => { const page = e.target.textContent; const tempBtn = e.target.getBoundingClientRect(); const center = (tempBtn.left + tempBtn.right) / 2; const bottom = tempBtn.bottom - 3; openSubmenu(page, { center, bottom }); };
3. Submenu添加空值判断与边界处理
在Submenu组件中,对page和links设置解构默认值,同时在渲染和useEffect中添加空值校验:
// Submenu.js import React, { useState, useRef, useEffect } from "react"; import {useGlobalContext} from '../../Context' const Submenu = () => { const { isSubmenuOpen, page: { page = '', links = [] }, // 解构时设置默认值 location, } = useGlobalContext(); const container = useRef(null); const [columns, setColumns] = useState("col-2"); useEffect(() => { if (!isSubmenuOpen || !location) return; // 子菜单关闭或无位置信息时不执行 setColumns("col-2"); const submenu = container.current; const { center, bottom } = location; submenu.style.left = `${center}px`; submenu.style.top = `${bottom}px`; if (links.length === 3) { setColumns("col-3"); } if (links.length > 3) { setColumns("col-4"); } }, [isSubmenuOpen, page, location, links]); return ( <aside className={`${isSubmenuOpen ? "submenu show" : "submenu"}`} ref={container} > {/* 仅在子菜单打开且有有效page时渲染内容 */} {isSubmenuOpen && page && ( <section> <h4>{page}</h4> <div className={`submenu-center ${columns}`}> {links.map((link, index) => { const { url, icon, label } = link; return ( <a key={index} href={url}> {icon} {label} </a> ); })} </div> </section> )} </aside> ); }; export default Submenu;
4. 确保App组件被GlobalProvider包裹
所有使用useGlobalContext的组件必须在GlobalProvider范围内,修改App.js:
// App.js import Navbar from "./Component/Navbar/Navbar"; import Submenu from "./Component/Submenu/Submenu"; import { GlobalProvider } from './Context'; function App() { return ( <GlobalProvider> <Navbar /> <Submenu /> </GlobalProvider> ); } export default App;
内容的提问来源于stack exchange,提问作者Nayan Biswas
相关产品推荐
相关产品推荐

