React+TypeScript点击按钮更新Navbar按钮样式失败求助
问题根源
useRef的核心特性是更新其current属性不会触发组件重渲染。你修改buttonDesign.current后,组件不会重新执行渲染逻辑,所以Button的variant属性始终读取初始值,样式自然不会更新。
两种可行解决方案
方案一:改用useState管理样式状态
把useRef换成useState,因为useState的状态更新会强制组件重渲染,这样Button就能读取到最新的variant值。
修改后的代码:
import { Button, Container, Nav, Navbar as NavbarBs } from "react-bootstrap"; import { NavLink } from "react-router-dom"; import { useState } from "react"; export function Navbar() { const [buttonVariant, setButtonVariant] = useState(""); const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => { const text = e.currentTarget.firstChild?.textContent; if (text === "Home") { setButtonVariant("outline-danger"); } else if (text === "Store") { setButtonVariant("outline-dark"); } }; return ( <NavbarBs fixed="top" style={{ height: "5vh", position: "fixed", width: "100%", background: "transparent", }} > <Container> <Nav className="d-flex justify-content-between w-100"> <Nav.Link to="/" as={NavLink}> <Button variant={buttonVariant} style={{ outline: "none", padding: "5px 50px 5px 50px", fontFamily: "Playfair Display, serif", fontSize: "1rem", }} onClick={handleClick} > Home </Button> </Nav.Link> <Nav.Link to="/store" as={NavLink}> <Button variant={buttonVariant} style={{ outline: "none", padding: "5px 50px 5px 50px", fontFamily: "Playfair Display, serif", fontSize: "1rem", }} onClick={handleClick} > Store </Button> </Nav.Link> <Nav.Link to="/about" as={NavLink}> <Button variant={buttonVariant} style={{ outline: "none", padding: "5px 50px 5px 50px", fontFamily: "Playfair Display, serif", fontSize: "1rem", }} > About </Button> </Nav.Link> </Nav> </Container> </NavbarBs> ); }
方案二:利用React Router NavLink的active状态(更推荐)
你的按钮本质是路由导航链接,NavLink会在当前路由匹配时自动添加active类,完全可以利用这个特性自动切换样式,不用手动处理点击事件,更符合路由场景的最佳实践。
示例代码(根据当前路由动态切换Button variant):
import { Button, Container, Nav, Navbar as NavbarBs } from "react-bootstrap"; import { NavLink, useLocation } from "react-router-dom"; export function Navbar() { const location = useLocation(); // 根据当前路由返回对应按钮的样式变体 const getButtonVariant = (path: string) => { if (location.pathname === path) { switch(path) { case "/": return "outline-danger"; case "/store": return "outline-dark"; default: return ""; } } return ""; }; return ( <NavbarBs fixed="top" style={{ height: "5vh", position: "fixed", width: "100%", background: "transparent", }} > <Container> <Nav className="d-flex justify-content-between w-100"> <Nav.Link to="/" as={NavLink}> <Button variant={getButtonVariant("/")} style={{ outline: "none", padding: "5px 50px 5px 50px", fontFamily: "Playfair Display, serif", fontSize: "1rem", }} > Home </Button> </Nav.Link> <Nav.Link to="/store" as={NavLink}> <Button variant={getButtonVariant("/store")} style={{ outline: "none", padding: "5px 50px 5px 50px", fontFamily: "Playfair Display, serif", fontSize: "1rem", }} > Store </Button> </Nav.Link> <Nav.Link to="/about" as={NavLink}> <Button variant={getButtonVariant("/about")} style={{ outline: "none", padding: "5px 50px 5px 50px", fontFamily: "Playfair Display, serif", fontSize: "1rem", }} > About </Button> </Nav.Link> </Nav> </Container> </NavbarBs> ); }
这个方案的好处是:路由切换时自动同步样式,不用维护额外的点击事件状态,逻辑更简洁可靠。
内容的提问来源于stack exchange,提问作者ether
相关产品推荐
相关产品推荐

