Soy nuevo en React y estoy intentando configurar un modo Bootstrap para mostrar mensajes de alerta.
En mi archivo principal App.js, tengo un controlador de errores que envía un componente Modal.js como un accesorio que activa el modal para que se muestre, por ejemplo:
En la aplicación.js:
function App() { const [modalShow, setModalShow] = useState(false); // Some other handlers const alertModalHandler = (modalMessage) => { console.log(modalMessage); setModalShow(true); } return ( // Other components. <AlertModal modalOpen={modalShow}/> ) }Y en Modal.js:
import React, { useState } from "react"; import Modal from "react-bootstrap/Modal"; import "bootstrap/dist/css/bootstrap.min.css"; const AlertModal = (props) => { const [isOpen, setIsOpen] = useState(false); if (props.modalOpen) { setIsOpen(true); } return ( <Modal show={isOpen}> <Modal.Header closeButton>Hi</Modal.Header> <Modal.Body>asdfasdf</Modal.Body> </Modal> ); }; export default AlertModal;Sin embargo, esto no funciona. me sale el error:
Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.Si cambio el componente Modal para que sea un componente 'tonto' y uso el accesorio directamente, por ejemplo:
const AlertModal = (props) => { return ( <Modal show={props.modalOpen}> <Modal.Header closeButton>Hi</Modal.Header> <Modal.Body>asdfasdf</Modal.Body> </Modal> ); };Funciona, pero también quería cambiar el estado mostrar/ocultar en el nivel del componente Modal.js, por ejemplo, tener algo que maneje los botones de cierre modales allí.
No entiendo por qué se rompe esto.
¿Y esto significa que tendré que manejar la función de cierre modal en el nivel principal de App.js?
Editar: contenido completo de app.js
import React, { useState } from 'react'; import './App.css'; import 'bootstrap/dist/css/bootstrap.css'; import AddUserForm from './components/addUserForm'; import UserList from './components/userList'; import AlertModal from './components/modal'; function App() { const [users, setUsers] = useState([]); const [modalShow, setModalShow] = useState(false); const addPersonHandler = (nameValue, ageValue) => { console.log(nameValue, ageValue); setUsers(prevUsers => { const updatedUsers = [...prevUsers]; updatedUsers.unshift({ name: nameValue, age: ageValue }); return updatedUsers; }); }; const alertModalHandler = (modalMessage) => { console.log(modalMessage); setModalShow(true); } let content = ( <p style={{ textAlign: 'center' }}>No users found. Maybe add one?</p> ); if (users.length > 0) { content = ( <UserList items={users} /> ); } return ( <> <div className="container"> <div className="row"> <div className="col-md-6 offset-md-3"> <AddUserForm onAddPerson={addPersonHandler} fireAlertModal={alertModalHandler}/> </div> </div> <div className="row"> <div className="col-md-6 offset-md-3"> {content} </div> </div> </div> <AlertModal modalOpen={modalShow}/> </> ); } export default App;Si ya envía un estado llamado modalShow al componente AlertModal , no hay razón para usar otro estado que haga lo mismo, como isOpen .
Cada vez que se cambia modalShow , provoca una nueva representación del componente AlertModal ya que cambió su estado, luego, si la propiedad es verdadera, establece otro estado, lo que provoca otra representación no necesaria cuando establece isOpen . Luego, en cada renderizado, si props.showModal no ha cambiado (y aún es cierto), activa setIsOpen una y otra vez.
Si desea controlar la apertura/cierre modal dentro de AlertModal , haría lo siguiente:
<AlertModal modalOpen={modalShow} setModalOpen={setModalShow}/>Pase la función set del estado showModal al componente modal, y allí utilícelo como mejor le parezca. Por ejemplo, en un controlador onClick.
modal.js:
import React, { useState } from "react"; import Modal from "react-bootstrap/Modal"; import "bootstrap/dist/css/bootstrap.min.css"; const AlertModal = (props) => { const onClickHandler = () => { props.setModalOpen(prevState => !prevState) } return ( <Modal show={props.modalOpen}> <Modal.Header closeButton>Hi</Modal.Header> <Modal.Body>asdfasdf</Modal.Body> </Modal> ); }; export default AlertModal;En tu modal.js
deberías poner
if (props.modalOpen) { setIsOpen(true); }en un efecto de uso.
React.useEffect(() => {if (props.modalOpen) { setIsOpen(true); }}, [props.modalOpen])Nunca debe llamar a setState así. Si lo hace, se ejecutará en cada renderizado y activará otro renderizado, porque cambió el estado. Debe colocar setModalShow junto con la cláusula if en un useEffect . P.ej:
useState(() => { if (modalOpen) { setIsOpen(true); } }, [modalOpen]) Tenga en cuenta que también reestructuré modalOpen fuera de props . De esa manera, useEffect solo se ejecutará cuando cambie modalOpen .