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

React+Tailwind实现导航点击/hover切换元素时无限重渲染问题求助

问题描述

我用React和Tailwind开发功能,需求是:导航按钮支持点击固定切换、悬停临时切换显示三个元素中的一个;初始默认显示Overview,悬停导航链接时临时展示对应元素,鼠标离开后恢复为选中的固定元素。但给导航链接加onClick监听后,出现无限重渲染错误:

Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.

相关代码:

const [displayOverview, setDisplayOverview] = useState(false);
const [displayProjects, setDisplayProjects] = useState(false);
const [displayDesigns, setDisplayDesigns] = useState(false);
const [selectedNavElement, setSelectedNavElement] = useState('overview');
const [displayFixed, setDisplayFixed] = useState(true)

<ul className='flex lg:text-left gap-24'>
    <li
        onMouseEnter={() => {setDisplayOverview(true); setDisplayFixed(false)}}
        onMouseLeave={() => {setDisplayOverview(false); setDisplayFixed(true)}}
    >
        Overview
    </li>
    <li
        onMouseEnter={() => {setDisplayDesigns(true); setDisplayFixed(false)}}
        onMouseLeave={() => {setDisplayDesigns(false); setDisplayFixed(true)}}
    >
        Designs
    </li>

    <li
        onMouseEnter={() => {setDisplayProjects(true); setDisplayFixed(false)}}
        onMouseLeave={() => {setDisplayProjects(false); setDisplayFixed(true)}}
    >
        <span onClick={setSelectedNavElement('projects')}>Projects</span>
    </li>
</ul>
</nav>
{/* Content */}
<section className='bg-red-500'>
    {displayOverview && <Overview />}
    {displayDesigns && <Designs />}
    {displayProjects && <Projects />}
    {(selectedNavElement === 'overview' && displayFixed === true) && <Overview />}
    {(selectedNavElement === 'designs' && displayFixed === true) && <Designs />}
    {(selectedNavElement === 'projects' && displayFixed === true) && <Projects />}

</section>
解决方案

1. 先修复无限重渲染问题

无限重渲染的直接原因是onClick绑定的不是函数,而是直接执行了setSelectedNavElement('projects')——每次组件渲染都会调用这个状态更新函数,触发新一轮渲染,形成循环。

把点击事件改成函数形式,其他导航项同理:

<span onClick={() => setSelectedNavElement('projects')}>Projects</span>

2. 优化状态管理(简化逻辑)

当前状态变量过多(三个displayXxx),可以合并成一个hoveredElement状态,用来记录当前悬停的元素标识,逻辑会更简洁:

  • 用hoveredElement存储当前悬停的元素('overview'/'designs'/'projects',无悬停时为null)
  • 保留selectedNavElement存储点击选中的固定元素
  • 渲染时优先判断是否有悬停元素,有则显示对应组件;无则显示选中的固定组件

3. 完整实现代码

import { useState } from 'react';
import Overview from './Overview';
import Designs from './Designs';
import Projects from './Projects';

function NavContent() {
    const [selectedNavElement, setSelectedNavElement] = useState('overview');
    const [hoveredElement, setHoveredElement] = useState(null);

    // 确定当前要显示的元素:悬停优先级高于选中
    const currentDisplay = hoveredElement || selectedNavElement;

    return (
        <>
            <nav>
                <ul className='flex lg:text-left gap-24'>
                    <li
                        onMouseEnter={() => setHoveredElement('overview')}
                        onMouseLeave={() => setHoveredElement(null)}
                        onClick={() => setSelectedNavElement('overview')}
                    >
                        Overview
                    </li>
                    <li
                        onMouseEnter={() => setHoveredElement('designs')}
                        onMouseLeave={() => setHoveredElement(null)}
                        onClick={() => setSelectedNavElement('designs')}
                    >
                        Designs
                    </li>
                    <li
                        onMouseEnter={() => setHoveredElement('projects')}
                        onMouseLeave={() => setHoveredElement(null)}
                        onClick={() => setSelectedNavElement('projects')}
                    >
                        Projects
                    </li>
                </ul>
            </nav>
            <section className='bg-red-500'>
                {currentDisplay === 'overview' && <Overview />}
                {currentDisplay === 'designs' && <Designs />}
                {currentDisplay === 'projects' && <Projects />}
            </section>
        </>
    );
}

export default NavContent;

逻辑说明

  • 悬停行为:鼠标进入导航项时设置hoveredElement,离开时清空,此时优先显示悬停对应的组件
  • 点击行为:点击导航项时更新selectedNavElement,鼠标离开后hoveredElement清空,自动切换到显示选中的固定组件
  • 初始状态:默认选中'overview',无悬停时直接显示Overview组件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 01:12:36