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

React组件Hover时大量重渲染问题修复求助

解决TechnologyItem hover时大量重渲染的问题

问题根源

核心问题有两点:

  • 每个TechnologyItem内部通过useSelector监听全局hoveredTechnology状态,该状态变化时所有子组件都会触发重渲染——React.memo只能阻止props变化导致的重渲染,无法干预组件内部selector状态变化引发的更新。
  • 你提到尝试了useCallback但未实际应用,导致onMouseOver/onMouseOut每次渲染都会生成新函数,干扰React.memo的生效逻辑。

解决方案

通过以下两步优化彻底解决问题:

1. 将hover状态判断移至父组件,通过props传递

在RingSection中统一处理hover状态,仅给需要更新的TechnologyItem传递变化的isHovered属性,避免所有子组件监听全局状态。

2. 用useCallback稳定事件函数,useMemo缓存过滤数组

确保子组件接收的props引用稳定,让React.memo能正确判断是否需要重渲染。


修改后的代码

RingSection.jsx

import React, { useMemo } from "react";
import { useSelector } from "react-redux";
import { activeQuadrantSelector, hoveredTechnologySelector } from "../../../store/selectors/quadrantSelectors";
import TechnologyItem from "../TechnologyItem/TechnologyItem";
import "./ringSection.scss";

const RingSection = ({ currentRing, currentRadarData }) => {
  const activeQuadrant = useSelector(activeQuadrantSelector);
  const hoveredTechnology = useSelector(hoveredTechnologySelector);

  // 用useMemo缓存过滤结果,避免每次渲染生成新数组
  const technologies = useMemo(() => {
    return currentRadarData.data.filter(
      ({ ring, quadrant }) =>
        ring === currentRing &&
        quadrant === currentRadarData.quadrants[activeQuadrant]
    );
  }, [currentRing, currentRadarData, activeQuadrant]);

  if (technologies.length === 0) {
    return null;
  }

  return (
    <div>
      <h3 className="ring-name">{currentRing}</h3>
      <div className="tech-items">
        {technologies.map(
          ({ index, name, technologyDescription, contacts, blipTag }) => (
            <TechnologyItem
              index={index}
              name={name}
              key={`${index}-${name}`}
              description={technologyDescription}
              contacts={contacts}
              tags={blipTag}
              // 父组件判断当前item是否hover,传递给子组件
              isHovered={name === hoveredTechnology}
            />
          )
        )}
      </div>
    </div>
  );
};

export default RingSection;

TechnologyItem.jsx

import React, { useCallback } from "react";
import { useDispatch } from "react-redux";
import { setHoveredTechnologyAction } from "../../../store/actions/quadrantActions";
import "./technologyItem.scss";

const TechnologyItem = ({ index, name, description, contacts, tags, isHovered }) => {
  const dispatch = useDispatch();

  // 用useCallback稳定事件函数,依赖dispatch和name
  const onMouseOver = useCallback(() => {
    dispatch(setHoveredTechnologyAction(name));
  }, [dispatch, name]);

  const onMouseOut = useCallback(() => {
    dispatch(setHoveredTechnologyAction(""));
  }, [dispatch]);

  return (
    <div
      className={isHovered ? "tech-item-highlighted" : "tech-item"}
      onMouseOver={onMouseOver}
      onMouseOut={onMouseOut}
    >
      <p>
        {index}. {name}
      </p>
    </div>
  );
};

export default React.memo(TechnologyItem);

优化效果说明

  • hover某个TechnologyItem时,仅该组件的isHovered属性变化会触发重渲染,其余组件因props未变化被React.memo阻止更新。
  • useMemo缓存过滤后的数组,避免父组件每次渲染生成新数组导致子组件不必要的更新。
  • useCallback稳定事件函数引用,确保子组件接收的事件处理函数不变,不会干扰React.memo的比较逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 16:22:13