如何在React.js中使用Context API管理全局状态并修复导航栏交互问题
问题原因与修复方案
1. 先修复Layout组件的Context作用域问题
你的ToggleProvider没有包裹实际渲染导航栏的children节点,导致Navbar根本拿不到ToggleContext的正确值,修改Layout.js代码:
function Layout ({startingTheme, startingToggle, children}) { return ( <> <ThemeProvider startingTheme={startingTheme} > <ToggleProvider startingToggle={startingToggle}> {/* 把children放到ToggleProvider内部,这样Navbar才能拿到切换状态 */} <LayoutNoToggleProvider> <LayoutNoThemeProvider >{children}</LayoutNoThemeProvider> </LayoutNoToggleProvider> </ToggleProvider> </ThemeProvider> </> ); }
同时修正LayoutNoToggleProvider里的类名判断逻辑,和useToggle的返回值类型对齐:
function LayoutNoToggleProvider ({children}) { const { toggle } = useContext(ToggleContext); return ( // 你的toggle是字符串类型,判断是否等于"show"即可 <div className={ toggle !== "show" ? "navbar navbar-collapsed" : "navbar navbar-collapse show" }> {children} </div> ) }
2. 修复Navbar的Context取值和点击事件
首先ToggleContext返回的是包含toggle状态和setToggle方法的对象,不能直接赋值给toggle变量,其次点击事件的逻辑完全错误,没有调用状态更新方法,修改Navbar.js代码:
// 解构出ToggleContext里的状态和方法 const { toggle, setToggle } = useContext(ToggleContext); // 主题Context也要解构,不然你拿到的也是整个对象,判断theme会出错 const { theme } = useContext(ThemeContext);
然后修改按钮的onClick事件:
<button onClick={ () => { // 切换状态:当前是show就设为空,否则设为show setToggle(toggle === "show" ? "" : "show") console.log("clicked") }} className="navbar-toggler collapsed" type="button" // 去掉bootstrap的data-bs-toggle属性,你已经用React控制状态了,不要让原生bootstrap和React冲突 // data-bs-toggle="collapsed" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded={toggle === "show"} aria-label="Toggle navigation" >
另外你Nav里重复写了两遍菜单DOM,完全没必要,直接根据toggle值动态改类名就可以,还可以补充菜单项点击关闭菜单的逻辑:
<div className={`navbar-collapse mt-2 ${toggle === "show" ? "show" : "collapsed"}`} id="navbarResponsive" > <ul className="navbar-nav text-uppercase ms-auto py-4 py-lg-0"> {navbarData.map((link,idx) => { return ( <li key={link.id}> <Link href={`/${link.ref}`} className="nav-item" data-index={idx} passHref> <a className="nav-link" onClick={() => { // 点击菜单项自动关闭菜单 setToggle("") console.log("菜单项被点击") }}> {link.title} </a> </Link> </li> ); })} </ul> </div>
3. 可选优化useToggle逻辑
如果不需要用字符串标识状态,直接用布尔值会更简单,修改useToggle.js:
import { useState } from "react"; function useToggle (startingToggle = false) { // 初始值转布尔值,避免传入字符串导致判断出错 const [toggle, setToggle] = useState(!!startingToggle); const toggleMenu = () => setToggle(prev => !prev) return { toggle, setToggle, toggleMenu } } export default useToggle;
改完之后按钮点击事件可以直接调用toggleMenu(),不需要手动判断状态。
内容的提问来源于stack exchange,提问作者Leo
相关产品推荐
相关产品推荐

