Next.js中无法正确传递列表项至子组件及类型标注问题
问题解决思路及代码修改
核心问题分析
- Modal始终显示最后一位成员:你在成员循环中给每个成员都渲染了一个
UserInfoModal,且所有Modal共用同一个showingUserInfoModal状态。当打开Modal时,所有Modal都会触发显示,最后一个Modal因层级覆盖会被优先看到,导致看起来只显示最后一位成员的信息。 - 类型错误:父组件通过
{...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
相关产品推荐
相关产品推荐

