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

React点击按钮后所有Div显示相同信息,如何实现指定Div展示专属信息?

问题分析

你的问题根源在于以下几点:

  1. 全局状态共享:你用单个project状态存储选中项目的详情,所有循环渲染的ProjectInfo组件都接收这个状态作为props,导致点击任意按钮后,所有组件都会显示同一个项目的信息。
  2. Fetch异步逻辑错误:getProjectInfo中你直接判断res.status,但res是fetch返回的Promise对象,并非HTTP响应,因此这个判断永远不会生效,后续的页面跳转也无法触发。
  3. 列表Key不规范:使用index作为列表项的key,当列表项顺序变化时会导致React渲染异常,应该使用唯一标识projectId作为key。
解决方案

针对上述问题,我们可以通过以下步骤修复:

  1. 维护选中项目状态:用selectedProject存储当前选中的项目详情,或同时存储selectedProjectId来标识哪个项目需要显示详情。
  2. 修正Fetch逻辑:在响应的回调中判断HTTP状态,并正确处理异步流程。
  3. 规范列表Key:使用projectId作为列表项的唯一key。
  4. 条件渲染详情组件:仅在当前项目被选中时,才渲染对应的ProjectInfo组件。
修正后的代码示例

ProjectInfo.js

import React from 'react';

// 修正props命名,更清晰地传递项目信息
const ProjectInfo = ({ project }) => {
    return (
        <div>
            {project.title}
            {/* 这里可以添加更多项目详情字段,比如description、projectTypes等 */}
        </div>
    );
};

export default ProjectInfo;

ProjectPage.js

import React, { useEffect, useState } from 'react';
import { useKeycloak } from "@react-keycloak/web";
import ProjectInfo from "./ProjectInfo";
import { useNavigate } from "react-router-dom";

const ProjectPage = () => {
    const { keycloak } = useKeycloak();
    const navigate = useNavigate();
    const [projectsList, setProjectsList] = useState([
        { projectId: "", projectUrl: "", description: '', projectTypes: "", title: '' }
    ]);
    // 存储当前选中的项目详情
    const [selectedProject, setSelectedProject] = useState(null);

    const getProjectInfo = (id) => {
        fetch(`http://localhost:8080/api/v1/user/get-one-project/${id}`, {
            method: 'GET',
            headers: {
                'Authorization': 'Bearer ' + keycloak.token,
                'content-type': 'application/json'
            },
        })
        .then(res => {
            // 先判断响应状态是否成功
            if (!res.ok) {
                throw new Error(`HTTP错误状态: ${res.status}`);
            }
            return res.json();
        })
        .then(response => {
            setSelectedProject(response);
            // 若需要跳转到详情页,在这里执行跳转
            // navigate("/project-info");
        })
        .catch(err => console.error('获取项目详情失败:', err));
    };

    useEffect(() => {
        fetch(`http://localhost:8080/api/v1/user/users-projects/${keycloak.tokenParsed.sub}`, {
            method: 'GET',
            headers: {
                'Authorization': 'Bearer ' + keycloak.token,
                'content-type': 'application/json'
            },
        })
        .then(res => res.json())
        .then(data => {
            setProjectsList(data);
            console.log(data);
        })
        .catch(err => console.error('获取项目列表失败:', err));
    }, [keycloak]);

    return (
        <div>
            {projectsList.map((p) => (
                // 使用projectId作为唯一key
                <div key={p.projectId} className="max-w-sm rounded overflow-hidden shadow-lg mx-auto">
                    <div className="px-6 py-4">
                        <div>{p.projectUrl}</div>
                        <div>{p.title}</div>
                        <div>{p.projectId}</div>
                        <div className="font-bold text-xl mb-2">
                            <button onClick={() => getProjectInfo(p.projectId)}>info</button>
                        </div>
                        {/* 仅当当前项目被选中时,渲染详情组件 */}
                        {selectedProject?.projectId === p.projectId && (
                            <div className="text-gray-700 text-base">
                                <ProjectInfo project={selectedProject} />
                            </div>
                        )}
                    </div>
                    <div className="px-6 pt-4 pb-2">
                        <span className="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2">#photography</span>
                        <span className="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2">#travel</span>
                        <span className="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2">#winter</span>
                    </div>
                </div>
            ))}
        </div>
    );
};

export default ProjectPage;

额外说明

如果你原本的需求是点击按钮后跳转到独立的详情页(/project-info),那么不需要在当前页面渲染ProjectInfo,而是在详情页中通过路由参数获取projectId,再调用接口获取详情进行展示。这种方式更符合单页应用的路由设计逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 20:35:16