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

React使用list.map渲染列表时如何仅打开当前项的Popup弹窗

问题描述
  • 在React项目中通过list.map遍历渲染用户列表时,点击单条用户的「View in popup」按钮,所有用户的弹窗会同步触发打开,预期仅打开当前点击用户对应的弹窗
  • 原实现代码如下:
export default function CreateForm() {
    const dispatch = useDispatch();
    const [isOpen, setIsOpen] = useState(false);

    return (
            <div className="display">
                {UsersList.map((user) => {
                    return (
                            <div>
                                <h1>{user.id}</h1>
                                <h1> {user.Name}</h1>
                                <h1> {user.userName}</h1>
                                   <button onClick={() => {
                                    dispatch(deleteUser({ id: beauty.id }));}}>
                                    Delete User
                                </button>
                                    <button onClick={()=>{
                                        setIsOpen(true);
                                    }}>View in popup</button>
                                    <Modal open={isOpen} onClose={()=>setIsOpen(false)}>
                                        <h2> {User.Information}</h2>
                                    </Modal>

                            </div>
                    );})}
            </div>
    );
}
问题原因

你的定位完全准确:所有map生成的列表项共用组件顶层的同一个布尔类型isOpen状态,一旦调用setIsOpen(true),所有绑定了open={isOpen}的Modal组件都会同步响应打开动作,最终出现所有弹窗同时弹出的现象。
另外原代码存在3处可一并修复的问题:

  • 删除用户逻辑中引用了未定义的beauty.id,实际应该取当前遍历项的user.id
  • 弹窗内容引用了未定义的User.Information,实际应该取当前遍历项的user.Information
  • map遍历生成的列表根元素缺少必填的唯一key属性,可能引发渲染异常
修复方案

方案1:将弹窗状态改为存储当前打开的用户ID(改动最小,适配当前简单场景)

不需要拆分组件,只需要把原来存布尔值的状态改为存储当前需要打开弹窗的用户ID,渲染Modal时仅判断「当前遍历项的userID是否等于状态里存的ID」,相等才打开即可。
修正后的完整代码:

export default function CreateForm() {
    const dispatch = useDispatch();
    // 替换原布尔值状态,默认null表示无弹窗打开
    const [openUserId, setOpenUserId] = useState(null);

    return (
            <div className="display">
                {UsersList.map((user) => {
                    return (
                            // 补充必填key属性
                            <div key={user.id}>
                                <h1>{user.id}</h1>
                                <h1>{user.Name}</h1>
                                <h1>{user.userName}</h1>
                                <button onClick={() => {
                                    // 修复id取值笔误
                                    dispatch(deleteUser({ id: user.id }));
                                }}>
                                    Delete User
                                </button>
                                <button onClick={()=>{
                                    // 点击时存入当前用户ID
                                    setOpenUserId(user.id);
                                }}>View in popup</button>
                                {/* 仅当前用户ID匹配状态值时弹窗打开 */}
                                <Modal open={openUserId === user.id} onClose={()=>setOpenUserId(null)}>
                                    {/* 修复用户信息取值笔误 */}
                                    <h2>{user.Information}</h2>
                                </Modal>
                            </div>
                    );})}
            </div>
    );
}

方案2:抽离单条用户项为独立组件(适配列表项逻辑复杂的场景)

如果后续单条用户项的交互逻辑会继续增加,可以把单条用户的渲染、交互逻辑抽成独立组件,每个组件实例维护自己的isOpen状态,天然不会互相干扰。
示例代码:

// 抽离独立的单条用户组件
function UserItem({ user }) {
    const dispatch = useDispatch();
    // 每个组件实例独立维护弹窗状态,互不影响
    const [isOpen, setIsOpen] = useState(false);

    return (
        <div>
            <h1>{user.id}</h1>
            <h1>{user.Name}</h1>
            <h1>{user.userName}</h1>
            <button onClick={() => {
                dispatch(deleteUser({ id: user.id }));
            }}>
                Delete User
            </button>
            <button onClick={()=> setIsOpen(true)}>View in popup</button>
            <Modal open={isOpen} onClose={()=>setIsOpen(false)}>
                <h2>{user.Information}</h2>
            </Modal>
        </div>
    )
}

// 原列表页组件仅负责遍历渲染
export default function CreateForm() {
    return (
            <div className="display">
                {UsersList.map((user) => <UserItem key={user.id} user={user} />)}
            </div>
    );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 01:36:26