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

React状态更新时组件数组重复初始化如何解决

问题说明

我在开发训练计划创建表单的周视图模块时,会先生成包含一周所有天的组件数组,通过currentDay状态控制具体渲染哪一天的内容。目前遇到的问题是:每次点击日期标签切换currentDay状态时,这个天数组都会被重新初始化——我在日期项的生成逻辑里加了console.log,每次切换都能看到全量日期的打印输出。

我期望的效果是:一次性生成所有天对应的组件数组,后续切换日期时直接从缓存的数组里取对应项渲染,不需要每次切换都重新创建整个数组。

目前已经尝试过的方案:

  • 抽离拆分WeekView、DayView独立组件
  • 使用useMemo钩子做缓存,但没有达到预期效果

复现代码如下:

import React, { useContext } from 'react';
import { ProgramContext } from '../state/context';
import { setCurrentDay } from '../state/reducer';
import { Tabs, TabWindow, WindowTab } from '../styled';
import DayView from './DayView';

const WeekView: React.FC = () => {
  const { state, dispatch } = useContext(ProgramContext);

  const handleDayClick = (index: number) => () => {
    if (index === state.currentDay) return;
    dispatch(setCurrentDay(index));
  };

  const days = [...Array(state.daysPerWeek).keys()]
    .map(i => i + state.currentWeek * state.daysPerWeek)
    .map(day => {
      console.log(day);
      return (
        <DayView key={day} day={day} />
      )
    });

  return (
    <TabWindow>
      <Tabs>
        {[...Array(state.daysPerWeek).keys()].map(day => {
          return (
            <WindowTab
              active={state.currentDay === day}
              key={day}
              onClick={handleDayClick(day)}
            >
              {`Dag ${(day % state.daysPerWeek) + 1}`}
            </WindowTab>
          )
        })}
      </Tabs>
      {days[state.currentDay]}
    </TabWindow>
  )
};

export default WeekView;
解决方案

你之前用useMemo没生效,核心原因是依赖项配置错误——这个天数组只和state.daysPerWeek、state.currentWeek两个值有关,和你切换的currentDay完全无关。如果你之前给useMemo传的依赖包含了整个state对象、或者误加了currentDay作为依赖,就会导致每次切换日期都重算数组,缓存失效。只要把这两个关联值作为依赖项传入useMemo,切换currentDay触发重渲染时就不会重新执行数组生成逻辑。

额外做两个优化可以进一步减少不必要的性能损耗:

  • 把标签点击的回调函数用useCallback缓存,避免每次渲染生成新的函数实例传给子组件
  • 给DayView组件包裹React.memo,只有传入的day属性变化时才重新渲染对应日期的组件

修改后的完整代码:

import React, { useContext, useMemo, useCallback } from 'react';
import { ProgramContext } from '../state/context';
import { setCurrentDay } from '../state/reducer';
import { Tabs, TabWindow, WindowTab } from '../styled';
import DayView from './DayView';

const WeekView: React.FC = () => {
  const { state, dispatch } = useContext(ProgramContext);

  // 缓存点击回调,dispatch本身是稳定不变的,仅当currentDay变化时更新回调
  const handleDayClick = useCallback((index: number) => {
    if (index === state.currentDay) return;
    dispatch(setCurrentDay(index));
  }, [dispatch, state.currentDay]);

  // 天数组仅在每周天数、当前周变化时重新生成,切换同周内日期不会触发重算
  const days = useMemo(() => {
    return [...Array(state.daysPerWeek).keys()]
      .map(i => i + state.currentWeek * state.daysPerWeek)
      .map(day => {
        console.log('初始化天组件:', day);
        return (
          <DayView key={day} day={day} />
        )
      });
  }, [state.daysPerWeek, state.currentWeek]);

  return (
    <TabWindow>
      <Tabs>
        {[...Array(state.daysPerWeek).keys()].map(day => {
          return (
            <WindowTab
              active={state.currentDay === day}
              key={day}
              onClick={() => handleDayClick(day)}
            >
              {`Dag ${(day % state.daysPerWeek) + 1}`}
            </WindowTab>
          )
        })}
      </Tabs>
      {days[state.currentDay]}
    </TabWindow>
  )
};

export default WeekView;

注意:DayView组件需要用React.memo包裹导出,写法参考export default React.memo(DayView),这样非当前展示的DayView不会因为父组件重渲染而跟着重渲染,性能提升会更明显。

改完之后可以验证:只有首次加载、切换周的时候才会打印天组件初始化的log,切换同周内的不同日期时,不会再触发全量的log打印,天数组只会在依赖变化时重新生成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 20:18:31