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

从Store渲染带不同ID的子组件时数据重复的解决方法

问题分析

所有子组件显示相同内容的核心原因是全局Store中的projectData是单例状态:当多个OneImage组件同时调用getProject时,后续请求返回的数据会覆盖Store中之前的数据,最终所有组件都会渲染最后一次请求的结果。另外还有两个次要问题:useEffect依赖数组缺失projectID,以及用index作为组件key的潜在风险。

解决方案

1. 重构Store,支持多项目数据存储

将Store中的状态从单个项目对象,改为以projectID为键的对象,这样每个项目的数据可以独立存储,不会互相覆盖。

示例Store修改(以Zustand为例):

const useProjectDataStore = create((set) => ({
  projects: {}, // 改为对象存储多个项目
  getProject: async (projectID) => {
    const res = await fetch(`/api/projects/${projectID}`);
    const data = await res.json();
    set((state) => ({
      projects: {
        ...state.projects,
        [projectID]: data // 按ID存储对应项目数据
      }
    }));
  }
}));

2. 修改OneImage组件,根据ID获取对应数据

更新组件逻辑,从Store中获取当前projectID对应的项目数据,并完善useEffect的依赖数组:

interface OneImageProps {
  projectID: string;
}

const OneImage: React.FC<OneImageProps> = ({ projectID }) => {
  const { projects, getProject } = useProjectDataStore();
  const projectData = projects[projectID] || {};

  useEffect(() => {
    // 避免重复请求,仅当未加载过该项目数据时发起请求
    if (!projects[projectID]) {
      getProject(projectID);
    }
  }, [projectID, getProject, projects]); // 添加必要依赖项

  // 处理加载状态,避免显示空内容或旧数据
  if (!projectData.picture) {
    return <div>加载中...</div>;
  }

  return (
    <div> 
      <img src={projectData.picture} alt={projectData.projectName} />
      <div>
        <a href="#">{projectData.projectName}</a>
      </div>
    </div>
  );
};

export default OneImage;

3. 优化MultiImages组件的key值

将key从index改为唯一的projectID,避免数组顺序变化时组件复用导致的异常:

const MultiImages: React.FC = () => {
  const values = ['500', '406', '614'];

  return ( 
    <div>
      {values.map((val) => {
        return <OneImage key={val} projectID={val} />;
      })}
    </div>
  );
};

export default MultiImages;

备选方案:组件内部管理状态(无需全局Store)

如果该组件不需要全局共享项目数据,可以去掉全局Store,让每个OneImage自己管理请求和状态:

interface OneImageProps {
  projectID: string;
}

const OneImage: React.FC<OneImageProps> = ({ projectID }) => {
  const [projectData, setProjectData] = useState<{ picture: string; projectName: string }>({
    picture: '',
    projectName: ''
  });
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchProject = async () => {
      setLoading(true);
      const res = await fetch(`/api/projects/${projectID}`);
      const data = await res.json();
      setProjectData(data);
      setLoading(false);
    };
    fetchProject();
  }, [projectID]);

  if (loading) {
    return <div>加载中...</div>;
  }

  return (
    <div> 
      <img src={projectData.picture} alt={projectData.projectName} />
      <div>
        <a href="#">{projectData.projectName}</a>
      </div>
    </div>
  );
};

export default OneImage;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 23:20:37