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

Next.js中无法正确传递列表项至子组件及类型标注问题

问题解决思路及代码修改

核心问题分析

  1. Modal始终显示最后一位成员:你在成员循环中给每个成员都渲染了一个UserInfoModal,且所有Modal共用同一个showingUserInfoModal状态。当打开Modal时,所有Modal都会触发显示,最后一个Modal因层级覆盖会被优先看到,导致看起来只显示最后一位成员的信息。
  2. 类型错误:父组件通过{...member}展开传递成员属性,但Modal的Props定义要求接收一个member对象,而非零散的属性。这导致Modal中解构后的member实际是成员的属性集合(如name、id),而非预期的User对象,因此访问member.name会触发类型错误。

代码修改方案

1. 父组件(ShowUsers)修改

  • 新增状态存储当前选中的成员,替代循环渲染多个Modal的写法,只保留一个Modal在循环外部。
  • 点击成员时,同时设置选中成员并打开Modal。

修改后的代码:

const ShowUsers = () => {
  const { householdId } = useContext(GlobalContext);
  const getHouseholdMembers = api.household.getHouseholdMembers.useQuery({
    householdId,
  });
  const [showingUserInfoModal, setShowingUserInfoModal] = useState(false);
  // 新增状态:存储当前选中的成员
  const [selectedMember, setSelectedMember] = useState<
    typeof getHouseholdMembers.data[0]["members"][number] | null
  >(null);

  return (
    <div className="flex flex-col justify-center">
      {getHouseholdMembers.data &&
        getHouseholdMembers.data[0]?.members.map((member) => (
          <div
            key={member.id}
            className="my-2 flex items-center gap-3"
          >
            <Image
              className="rounded-full"
              src={member.image ?? ""}
              width={40}
              height={40}
              alt={member.name ?? ""}
            />
            <div className="flex flex-col">
              <h3
                className="text-lg"
                // 点击时设置选中成员并打开Modal
                onClick={() => {
                  setSelectedMember(member);
                  setShowingUserInfoModal(true);
                }}
              >
                {member.name}
              </h3>
              <p className="italic">
                {member.role === "USER" ? "Member" : "Founder"}
              </p>
            </div>
          </div>
        ))}
      {/* 将Modal移到循环外部,只渲染一个 */}
      <UserInfoModal
        showingUserInfoModal={showingUserInfoModal}
        setShowingUserInfoModal={setShowingUserInfoModal}
        member={selectedMember}
      />
    </div>
  );
};

2. Modal组件(UserInfoModal)修改

  • 调整Props类型,将member设为可选(因为初始时无选中成员)。
  • 直接解构member对象,使用可选链避免undefined报错。

修改后的代码:

type UserInfoModalProps = {
  showingUserInfoModal: boolean;
  setShowingUserInfoModal: React.Dispatch<SetStateAction<boolean>>;
  // 将member设为可选类型
  member?: RouterOutputs["household"]["getHouseholdMembers"][0]["members"][number];
};

const UserInfoModal = ({
  showingUserInfoModal,
  setShowingUserInfoModal,
  member,
}: UserInfoModalProps) => {
  return (
    <div>
      <Modal
        isOpen={showingUserInfoModal}
        onClose={() => setShowingUserInfoModal(false)}
      >
        {/* 使用可选链避免成员为null时的报错 */}
        <div className="">{member?.name}</div>
      </Modal>
    </div>
  );
};

额外说明

  • 如果需要确保Modal只有在选中成员时才渲染,可以给Modal加上条件判断:{selectedMember && <UserInfoModal ... />}。
  • 可选链member?.name能有效避免编译时的undefined报错,符合TypeScript的类型安全要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 12:35:13