You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React跨路由滚动组件时ref未定义问题求助

解决React跨路由滚动到指定组件的问题

问题背景

项目中Navbar按钮点击后需滚动到HomePage嵌套的Projects组件内指定div,在HomePage(/home)路由下用forwardRef实现正常,但从GameZone(/home/game_zone)路由点击按钮时,导航到HomePage后ref未定义,尝试Context存ref、flushSync触发DOM重载均无效。

核心原因

跨路由时,GameZone组件内的ref无法指向HomePage中渲染的Projects组件——两个路由的组件是独立实例,导航后HomePage才会挂载并初始化ref,此时GameZone中的滚动逻辑已执行完毕,导致ref为null。

解决方案

方法一:路由状态传递 + useEffect监听

通过React Router的state传递滚动指令,在HomePage挂载/路由状态变化时执行滚动。

修改代码:

  1. GameZone组件:导航时携带滚动标记
import { useNavigate } from "react-router-dom";
import Header from './Header';

function GameZone() {
    const navigate = useNavigate();

    const handleClickScroll = () => {
        navigate("/home", { state: { scrollToProjects: true } });
    }

    return ( 
        <>
            <div className="gamezone-content">
                <Header handleClickScroll={handleClickScroll}/>
            </div>
        </>
    );
}

export default GameZone;
  1. HomePage组件:监听路由状态,触发滚动
import { useRef, useEffect } from 'react';
import { useLocation, useNavigate } from "react-router-dom";
import Header from './Header';
import Projects from './Projects';

function HomePage() {
    const ref = useRef(null);
    const navigate = useNavigate();
    const location = useLocation();

    useEffect(() => {
        if (location.state?.scrollToProjects) {
            ref.current?.scrollIntoView({ behavior: 'smooth' });
            // 清除路由状态,避免刷新/回退时重复滚动
            navigate(location.pathname, { replace: true, state: {} });
        }
    }, [location.state, navigate, ref]);

    const handleClickScroll = () => {
        ref.current?.scrollIntoView({ behavior: 'smooth' });
    }

    return (   
        <div className="homepage">
            <Header handleClickScroll={handleClickScroll}/>
            <div className="content"></div>
            <Projects ref={ref}/>      
            <div className='footer'></div>
        </div>
    );
}

export default HomePage;

方法二:利用浏览器锚点(更简单)

给Projects的div设置id,直接导航到带锚点的URL,浏览器自动滚动。

修改代码:

  1. Projects组件:保留id(原代码已存在)
import { forwardRef } from 'react';
const Projects = forwardRef((props, ref) => {
  return (
    <div className="projects-content" id="projects" ref={ref}> 
    </div>
  );
}) 
  1. GameZone组件:导航到带锚点的HomePage
import { useNavigate } from "react-router-dom";
import Header from './Header';

function GameZone() {
    const navigate = useNavigate();

    const handleClickScroll = () => {
        navigate("/home#projects");
    }

    return ( 
        <>
            <div className="gamezone-content">
                <Header handleClickScroll={handleClickScroll}/>
            </div>
        </>
    );
}

export default GameZone;
  1. HomePage组件:内部点击直接滚动(或利用锚点)
import { useRef } from 'react';
import Header from './Header';
import Projects from './Projects';

function HomePage() {
    const ref = useRef(null);

    const handleClickScroll = () => {
        ref.current?.scrollIntoView({ behavior: 'smooth' });
        // 或者用锚点:window.location.hash = "#projects";
    }

    return (   
        <div className="homepage">
            <Header handleClickScroll={handleClickScroll}/>
            <div className="content"></div>
            <Projects ref={ref}/>      
            <div className='footer'></div>
        </div>
    );
}

export default HomePage;

方法对比

  • 路由状态法:支持自定义滚动逻辑,适合复杂场景;
  • 锚点法:代码量少,依赖浏览器原生行为,适合基础需求。

内容的提问来源于stack exchange,提问作者spider

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 04:55:05