Tengo un componente desplegable que es solo un Modal nativo de React colocado junto a un interruptor: el Modal me permite hacer que todo el fondo Pressable para poder cerrar el menú desplegable cuando se presiona cualquier área fuera de él.
Cada uno de los elementos dentro del menú desplegable tiene un accesorio onPress que realiza una función determinada al mismo tiempo que cierra el menú desplegable. Esto funciona muy bien, excepto cuando quiero usar el evento onPress para abrir otro Modal nativo de reacción.
He aquí un ejemplo (simplificado):
<> // 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> </> Esto funciona como se esperaba en la web: el Modal del menú desplegable se cierra y el otro Modal se abre al mismo tiempo. Sin embargo, en iOS, el segundo Modal nunca se abre y la aplicación deja de responder por completo hasta que la reinicio desde el generador de Metro.
He visto otras preguntas en Stack Overflow que mencionan "abrir un modal desde dentro de otro modal", pero todas las preguntas existentes parecen referirse a los modales anidados. En mi caso, en realidad no estamos tratando de anidar modales: el segundo modal debería abrirse cuando se cierra el primero. La aplicación de iOS parece no representar el segundo modal, aunque puedo verificar a través de la consola que el booleano isModalOpen se está configurando como verdadero.
Estoy empezando a pensar que esto es en realidad un error con React Native en sí mismo, pero pensé en verificar aquí en caso de que sea un problema conocido, ¿tal vez con el burbujeo de eventos o algo así?
Puede usar InteractionManager dentro de su primer useEffect modal. eso garantiza que su segundo modal se abrirá después de que finalice la primera animación modal.
InteractionManager.runAfterInteractions(() => { // ...long-running synchronous task... });más detalles: https://reactnative.dev/docs/interactionmanager
Entonces, al final del día, el problema es que React Native simplemente no mostrará dos modales al mismo tiempo ; esta limitación se aplica incluso si intenta abrir una nueva modalidad mientras la animación de cierre de la anterior aún está terminando. .
Parece que algunas personas manejan esto con un tiempo de espera, pero eso resultó poco confiable en mis pruebas. Un tiempo de espera también se basa en un número mágico, cuando el quid de la cuestión es que el modal aún tiene que desmontarse antes de abrir uno nuevo.
Para resolver esto, agregué una variable de estado llamada queuedPress al proveedor de contexto de mi menú desplegable que almacena la función onPress del elemento de menú que se acaba de presionar. También agregué una devolución de llamada afterClose que se ejecuta cuando se completa la animación de cierre del menú desplegable. Cuando se presiona un elemento desplegable, almaceno su función onPress , luego afterClose maneja la llamada real. Esto garantiza que onPress esté en cola durante el tiempo que la animación tarde en completarse, por lo que se garantizará que el modal abierto desde dentro de ese onPress se abra después de que el menú desplegable ya esté cerrado.
Dependiendo de su código, su implementación puede variar enormemente, pero en mi caso, esta es otra situación en la que useContext ha salvado el día. Cualquier solución que limite el número de modales abiertos a 1 debería funcionar.
Esta es una limitación conocida en react-native
pero como solución
setTimeout para el segundo modal después de cerrar el primer modal 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;