BrowserRouter的Link覆盖onClick事件导致State Hook更新失败如何解决
问题根因
你遇到的问题有两个核心原因:
- 你给自定义
Card组件传入的onClick没有生效:如果Card组件内部没有将接收的onClick属性绑定到自身的根DOM节点上,外层传入的点击事件本身就不会触发。 - 即使
onClick能触发,setTask是React的异步状态更新,而Link的跳转行为会优先执行,跳转后Home组件直接卸载,状态更新逻辑还没执行就被中断了,同时Home组件内部的state是组件私有数据,也无法直接传递给跳转后的PlayerPage组件。
解决方案
不需要额外维护Home的state,直接用React Router自带的路由传参能力实现需求,修改代码如下:
修改后的Home.js代码
import { Link } from "react-router-dom"; import { useState, useEffect } from "react"; export default function Home() { return ( <> <Header /> <main className="home-main"> <div className="main-wrap"> <section className="card-container"> <h1>Good Morning</h1> <h1>Choose Your Work Style</h1> <div className="card-wrap"> {/* 把要传递的参数放在Link的state属性里,点击事件直接写在Link上更稳妥 */} <Link to={{ pathname: "/PlayerPage", state: { task: 'Short Task' } }} onClick={() => console.log('点击触发,将要传递的task值为:Short Task')} > <Card taskName="Short Task" description="Lorem ipsum dolor sit amet, consectetur adipiscing elit." /> </Link> </div> </section> </div> </main> </> ); }
修改后的PlayerPage.js代码
import { useLocation } from "react-router-dom"; import Header from "../components/Header"; import Timer from "../components/Timer"; import "./PlayerPage.scss"; export default function PlayerPage() { // 用useLocation钩子接收路由传递的参数 const location = useLocation(); const task = location.state?.task; return ( <> <Header /> <main className="player-page-main"> <div className="player-page-main-wrap"> <div className="timer-title-wrap"> <Timer /> <h2 className="task-title">{task || '未选择任务'}</h2> </div> </div> </main> </> ); }
可选方案:必须先更新state再跳转的场景
如果你确实需要先执行Home的状态更新逻辑再跳转,可以不用Link组件,改用useNavigate钩子手动控制跳转时机:
import { useNavigate } from "react-router-dom"; import { useState, useEffect } from "react"; export default function Home() { const [task, setTask] = useState(); const navigate = useNavigate(); useEffect(() => { console.log(task); // 状态更新完成后再跳转 if(task) { navigate('/PlayerPage', { state: { task } }) } },[task, navigate]) const handleCardClick = () => { setTask('Short Task') } return ( <> <Header /> <main className="home-main"> <div className="main-wrap"> <section className="card-container"> <h1>Good Morning</h1> <h1>Choose Your Work Style</h1> <div className="card-wrap"> {/* 注意要确保Card组件内部接收onClick并绑定到根DOM节点,点击事件才会生效 */} <Card onClick={handleCardClick} taskName="Short Task" description="Lorem ipsum dolor sit amet, consectetur adipiscing elit." /> </div> </section> </div> </main> </> ); }
内容的提问来源于stack exchange,提问作者OJM
相关产品推荐
相关产品推荐

