从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
相关产品推荐
相关产品推荐

