React Native:在 iOS 中无法从另一个模态框内打开一个模态框
React Native: Opening a Modal from inside another Modal doesn't work in iOS
我有一个下拉组件,它只是一个位于开关旁边的 React Native Modal
- Modal
允许我将整个背景设为 Pressable
这样我就可以关闭按下下拉框以外的任何区域时的下拉框。
下拉菜单中的每个项目都有一个 onPress
道具,它执行给定的功能,同时也关闭下拉菜单本身。这很好用,除非我想使用 onPress
事件打开另一个反应本机 Modal
.
这是一个(简化的)示例:
<>
// Custom component that renders a react-native Modal
<Dropdown
items={[
{ label: "Press to open a Modal", onPress: () => setIsModalOpen(true) }
]}
/>
// Another react-native Modal
<Modal visible={isModalOpen}>
...
</Modal>
</>
这在网络上按预期工作 - 下拉菜单的 Modal
关闭,同时另一个 Modal
打开。但是,在 iOS 上,第二个 Modal
永远不会打开,并且应用程序实际上变得完全没有响应,直到我从 Metro builder 重新启动它。
我在 Stack Overflow 上看到其他提到“从另一个模态中打开一个模态”的问题,但现有的问题似乎都与嵌套模态有关。在我的例子中,我们实际上并没有试图嵌套模态——第二个模态应该在第一个模态关闭时打开。 iOS 应用程序似乎只是不呈现第二个模态,即使我可以通过控制台验证 isModalOpen
布尔值是否设置为 true。
我开始认为这实际上是 React Native 本身的错误,但我想我会检查这里以防它是一个已知问题,可能与事件冒泡或其他问题有关?
这是 react-native
中的 a known limitation
但作为解决方法
- 您可以在关闭第一个模态后对第二个模态使用
setTimeout
- 使用条件渲染,以便它根据可见性
注册(mount/unmount)到dom第二个模态
import React, {useCallback, useState} from 'react';
import {Button, Modal, Text, View} from 'react-native';
const App = () => {
const [is1stModalVisible, setIs1stModalVisible] = useState(false);
const [is2ndModalVisible, setIs2ndModalVisible] = useState(false);
const onOpen2ndModal = useCallback(() => {
// closes the 1st modal
setIs1stModalVisible(false);
// open the 2nd modal
setTimeout(
() => {
setIs2ndModalVisible(true);
},
// any small number will do, maybe animation duration
100,
);
}, []);
return (
<View>
<Button
title="Open 1st modal"
onPress={() => setIs1stModalVisible(true)}
/>
<Modal visible={is1stModalVisible}>
<Text>Modal 1 content</Text>
<Button title="Open 2nd modal" onPress={onOpen2ndModal} />
</Modal>
{is2ndModalVisible ? (
<Modal visible={is2ndModalVisible}>
<Text>Modal 2 content</Text>
<Button
title="Close 2nd modal"
onPress={() => setIs2ndModalVisible(false)}
/>
</Modal>
) : null}
</View>
);
};
export default App;
所以归根结底,问题是 React Native 根本不会同时显示两个模式 - 即使您正在尝试,此限制也适用在前一个模式的关闭动画仍在结束时打开一个新模式。
似乎有人用超时来处理这个问题,但在我的测试中证明这是不可靠的。超时也依赖于一个神奇的数字,当问题的症结在于模态在打开一个新模态之前尚未卸载。
为了解决这个问题,我在我的下拉菜单的上下文提供程序中添加了一个名为 queuedPress
的状态变量,用于存储刚刚按下的菜单项中的 onPress
功能。我还添加了一个 afterClose
回调,它在下拉菜单的关闭动画完成时运行。按下下拉项时,我存储其 onPress
函数,然后 afterClose
处理实际调用。这确保 onPress
在动画完成时排队等待,因此从 onPress
中打开的模式将保证在下拉列表已经关闭后打开。
根据您的代码,您的实现可能会有很大差异,但就我而言,这是 useContext
挽救局面的另一种情况。任何将打开模式的数量限制为 1 的解决方案都应该有效。
我有一个下拉组件,它只是一个位于开关旁边的 React Native Modal
- Modal
允许我将整个背景设为 Pressable
这样我就可以关闭按下下拉框以外的任何区域时的下拉框。
下拉菜单中的每个项目都有一个 onPress
道具,它执行给定的功能,同时也关闭下拉菜单本身。这很好用,除非我想使用 onPress
事件打开另一个反应本机 Modal
.
这是一个(简化的)示例:
<>
// Custom component that renders a react-native Modal
<Dropdown
items={[
{ label: "Press to open a Modal", onPress: () => setIsModalOpen(true) }
]}
/>
// Another react-native Modal
<Modal visible={isModalOpen}>
...
</Modal>
</>
这在网络上按预期工作 - 下拉菜单的 Modal
关闭,同时另一个 Modal
打开。但是,在 iOS 上,第二个 Modal
永远不会打开,并且应用程序实际上变得完全没有响应,直到我从 Metro builder 重新启动它。
我在 Stack Overflow 上看到其他提到“从另一个模态中打开一个模态”的问题,但现有的问题似乎都与嵌套模态有关。在我的例子中,我们实际上并没有试图嵌套模态——第二个模态应该在第一个模态关闭时打开。 iOS 应用程序似乎只是不呈现第二个模态,即使我可以通过控制台验证 isModalOpen
布尔值是否设置为 true。
我开始认为这实际上是 React Native 本身的错误,但我想我会检查这里以防它是一个已知问题,可能与事件冒泡或其他问题有关?
这是 react-native
但作为解决方法
- 您可以在关闭第一个模态后对第二个模态使用
setTimeout
- 使用条件渲染,以便它根据可见性 注册(mount/unmount)到dom第二个模态
import React, {useCallback, useState} from 'react';
import {Button, Modal, Text, View} from 'react-native';
const App = () => {
const [is1stModalVisible, setIs1stModalVisible] = useState(false);
const [is2ndModalVisible, setIs2ndModalVisible] = useState(false);
const onOpen2ndModal = useCallback(() => {
// closes the 1st modal
setIs1stModalVisible(false);
// open the 2nd modal
setTimeout(
() => {
setIs2ndModalVisible(true);
},
// any small number will do, maybe animation duration
100,
);
}, []);
return (
<View>
<Button
title="Open 1st modal"
onPress={() => setIs1stModalVisible(true)}
/>
<Modal visible={is1stModalVisible}>
<Text>Modal 1 content</Text>
<Button title="Open 2nd modal" onPress={onOpen2ndModal} />
</Modal>
{is2ndModalVisible ? (
<Modal visible={is2ndModalVisible}>
<Text>Modal 2 content</Text>
<Button
title="Close 2nd modal"
onPress={() => setIs2ndModalVisible(false)}
/>
</Modal>
) : null}
</View>
);
};
export default App;
所以归根结底,问题是 React Native 根本不会同时显示两个模式 - 即使您正在尝试,此限制也适用在前一个模式的关闭动画仍在结束时打开一个新模式。
似乎有人用超时来处理这个问题,但在我的测试中证明这是不可靠的。超时也依赖于一个神奇的数字,当问题的症结在于模态在打开一个新模态之前尚未卸载。
为了解决这个问题,我在我的下拉菜单的上下文提供程序中添加了一个名为 queuedPress
的状态变量,用于存储刚刚按下的菜单项中的 onPress
功能。我还添加了一个 afterClose
回调,它在下拉菜单的关闭动画完成时运行。按下下拉项时,我存储其 onPress
函数,然后 afterClose
处理实际调用。这确保 onPress
在动画完成时排队等待,因此从 onPress
中打开的模式将保证在下拉列表已经关闭后打开。
根据您的代码,您的实现可能会有很大差异,但就我而言,这是 useContext
挽救局面的另一种情况。任何将打开模式的数量限制为 1 的解决方案都应该有效。