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

React Native模态框调用父组件deletePlayer函数异常问题

问题原因分析

这个问题我之前也碰到过!核心原因是所有Player子组件共享了父组件中同一个showDeleteDialog布尔状态:

  • 当你点击任意玩家的名字时,父组件的showDeleteDialog变为true,这会触发所有Player组件里的Modal同时渲染(视觉上多个Modal重叠,你以为只有一个,但实际最后一个Modal会在最上层)。
  • 当点击"Yes"按钮时,由于循环渲染的变量捕获特性,事件处理函数会绑定最后一次循环的player变量,所以无论点击哪个玩家,最终打印的都是最后一个玩家的信息。

而直接在Pressable的onPress里调用deletePlayer(player)能正常工作,是因为每个Pressable的事件处理函数都独立捕获了当前循环对应的player变量,没有共享状态的干扰。

两种解决方案

方案一:将模态框状态移到Player子组件内部

把showDeleteDialog的状态从父组件下沉到每个Player组件里,让每个玩家拥有独立的模态框控制逻辑,彻底避免状态共享的问题。

修改后的Player.tsx

import { useState } from 'react';
import { Pressable, Text, Modal, View, Button } from 'react-native';

const Player = ({ player, deletePlayer }) => {
    // 每个子组件独立维护模态框状态
    const [showDeleteDialog, setShowDeleteDialog] = useState(false);

    const closeDialog = () => setShowDeleteDialog(false);

    return (
        <>
            <Pressable onPress={() => setShowDeleteDialog(true)}>
                <Text>{player.name}</Text>
            </Pressable>
            {showDeleteDialog && (
                <Modal animationType="fade" transparent onRequestClose={closeDialog}>
                    <InnerContainer innerWidth={innerWidth!}>
                        <Text>Delete {player.name}?</Text>
                        <View>
                            <Button
                                title="Yes"
                                onPress={() => {
                                    deletePlayer(player);
                                    closeDialog();
                                }}
                            />
                            <Button
                                title="No"
                                onPress={closeDialog}
                            />
                        </View>
                    </InnerContainer>
                </Modal>
            )}
        </>
    );
};

export default Player;

简化后的Players.tsx

import { View } from 'react-native';
import Player from './Player';

const Players = () => {
    const deletePlayer = (player) => {
        console.log(player);
    };

    return (
        <View>
            {players.map((player) => (
                <Player
                    player={player}
                    key={player.id}
                    deletePlayer={deletePlayer}
                />
            ))}
        </View>
    );
};

export default Players;

方案二:父组件维护当前要删除的玩家ID

如果需要父组件统一管理模态框(比如控制全局位置、样式),可以让父组件维护一个currentDeletingPlayerId状态,替代原来的布尔值,确保模态框只对应一个玩家。

修改后的Players.tsx

import { useState } from 'react';
import { View, Modal, Button, Text } from 'react-native';
import Player from './Player';

const Players = () => {
    // 存储当前要删除的玩家ID,初始为null表示没有要删除的玩家
    const [currentDeletingPlayerId, setCurrentDeletingPlayerId] = useState<string | null>(null);

    const deletePlayer = (player) => {
        console.log(player);
        setCurrentDeletingPlayerId(null); // 删除完成后关闭模态框
    };

    // 根据ID找到当前要删除的玩家
    const currentPlayer = players.find(p => p.id === currentDeletingPlayerId);

    return (
        <View>
            {players.map((player) => (
                <Player
                    player={player}
                    key={player.id}
                    setCurrentDeletingPlayerId={setCurrentDeletingPlayerId}
                />
            ))}
            {/* 父组件统一渲染模态框,只有当有要删除的玩家时才显示 */}
            {currentPlayer && (
                <Modal animationType="fade" transparent onRequestClose={() => setCurrentDeletingPlayerId(null)}>
                    <InnerContainer innerWidth={innerWidth!}>
                        <Text>Delete {currentPlayer.name}?</Text>
                        <View>
                            <Button
                                title="Yes"
                                onPress={() => deletePlayer(currentPlayer)}
                            />
                            <Button
                                title="No"
                                onPress={() => setCurrentDeletingPlayerId(null)}
                            />
                        </View>
                    </InnerContainer>
                </Modal>
            )}
        </View>
    );
};

export default Players;

简化后的Player.tsx

import { Pressable, Text } from 'react-native';

const Player = ({ player, setCurrentDeletingPlayerId }) => {
    return (
        <Pressable onPress={() => setCurrentDeletingPlayerId(player.id)}>
            <Text>{player.name}</Text>
        </Pressable>
    );
};

export default Player;
总结

两种方案都能解决你的问题:

  • 方案一更简单直观,适合每个玩家独立控制模态框的场景;
  • 方案二更适合需要全局统一管理模态框的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 09:55:14