React Native :在iOS中无法从一个Modal内部打开另一个Modal

wnavrhmk  于 2022-11-30  发布在  React
关注(0)|答案(4)|浏览(484)

我有一个Dropdown组件,它只是一个位于toggle旁边的React Native Modal-Modal允许我将整个背景设置为Pressable,这样我就可以在按下下拉列表以外的任何区域时关闭下拉列表。
下拉菜单中的每一项都有一个onPress prop,它在关闭下拉菜单的同时执行给定的功能。这很好用,除非我想用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本身的一个bug,但是我想我应该在这里检查一下,以防它是一个已知的问题,也许是事件冒泡之类的?

vatpfxk5

vatpfxk51#

您可以在第一个模态useEffect中使用InteractionManager。这保证了第二个模态将在第一个模态动画完成后打开。

InteractionManager.runAfterInteractions(() => {
   // ...long-running synchronous task...
 });

更多详情:https://reactnative.dev/docs/interactionmanager

35g0bw71

35g0bw712#

这是react-native中的已知限制
但作为一个"变通办法"
1.您可以在关闭第一个模态后,对第二个模态使用setTimeout
1.使用条件渲染,因此它根据可见性将第二模态注册(安装/卸载)到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;
sd2nnvve

sd2nnvve3#

因此,归根结底,问题在于React Native无法同时显示两个模态-即使您在前一个模态的结束动画尚未完成时尝试打开新模态,此限制也适用。

看起来有些人用超时来处理这个问题,但在我的测试中证明这是不可靠的。超时也依赖于一个神奇的数字,当问题的关键是模态在打开一个新的模态之前还没有卸载时。
为了解决这个问题,我在Dropdown菜单的上下文提供器中添加了一个名为queuedPress的状态变量,用于存储刚刚按下的菜单项的onPress函数。我还添加了一个afterClose回调函数,用于在Dropdown菜单的关闭动画完成时运行。当按下Dropdown项时,我存储其onPress函数,则afterClose处理实际的调用,这确保了onPress在动画完成之前一直处于队列中,因此从该onPress中打开的模态将保证在下拉菜单关闭之后打开。
根据您的代码,您的实现可能会有很大的不同,但在我的例子中,这是useContext的另一种情况。任何将开放模态的数量限制为1的解决方案都应该有效。

cbwuti44

cbwuti444#

我们可以在第一个模态上使用onModalHide属性来触发第二个模态的打开,而不是使用超时来触发第二个模态的打开。
onModalAttribute仅在第一个模态关闭后调用。
然而,这并没有来自react-native的标准Modal。我们需要使用react-native-modal包来实现这个特性。它只提供了额外的特性,所以应该不难实现。

相关问题