Necesito implementar un modal reutilizable. Tengo básicamente dos implementaciones en mi mente.
const Modal = (props) => { return ( <div> <button onClick={() => props.setVisibility(false)}>Cancel</button> </div> ); }; export default function App() { const [showModal, setShowModal] = useState(false); return ( <div className="App"> <button onClick={() => setShowModal((p) => !p)}>Toggle Modal</button> {showModal && <Modal setShowModal={setShowModal} />} </div> ); }imperativeHandle . const Modal = React.forwardRef((props, ref) => { const [showModal, setShowModal] = useState(false); useImperativeHandle(ref, () => ({ hide: () => setShowModal(false), show: () => setShowModal(true), toggle: () => setShowModal((p) => !p) })); if (!showModal) return null; return ( <div> <button onClick={() => setShowModal(false)}>Cancel</button> </div> ); }); export default function App() { const modal = useRef(); return ( <div className="App"> <button onClick={() => modal.current.toggle()}>Toggle Modal</button> <Modal ref={modal} /> </div> ); }Prefiero el segundo, ya que creo que se ve más limpio, sin un montón de estados que contaminen el componente principal (habrá múltiples modales en una página). La función de alternar solo está ahí para el ejemplo, solo necesitaré las funciones mostrar y ocultar. Además, la visibilidad del modal es una propiedad del modal, y creo que el modal debería ser el componente que lo maneje. Pero he escuchado a personas e incluso a los documentos de reacción decir
El código imperativo que usa referencias debe evitarse en la mayoría de los casos.
Entonces, aunque creo que este es un uso aceptable de las referencias, eso es lo que me detiene. Quiero saber,
Respecto a ti 3 preguntas:
La forma de reacción es definitivamente la forma sin useImperativeHandle . El código de reacción debe ser declarativo, no imperativo.
No sé sobre el rendimiento. No esperaría una gran diferencia.
El useImperativeHandle técnicamente funcionará bien , no habrá errores inmediatos. Pero la idea detrás de la forma de reaccionar es mantener el código mantenible, fácil de entender y evitar futuros errores y confusiones.
Imagine que de repente necesita abrir/cerrar un modal de múltiples componentes. Si el estado está en el padre, este cambio es simple, puede pasar fácilmente el estado y la devolución de llamada setState donde quiera.
Si usa useImperativeHandle , debe asegurarse de que el estado sea consistente, lo que en esencia significa manejar el estado en algún componente principal de todos modos.
O imagine que decide (o necesita) refactorizar para usar un patrón reductor y dispatch una acción openModal en lugar de llamar al "método" show de su componente. Nuevamente, eso es fácil si solo maneja estados y devoluciones de llamada de todos modos.
Entiendo totalmente su deseo de mantener el estado dentro del modal. Siento lo mismo (y estaría feliz de ser corregido aquí). Pero también estoy feliz una y otra vez de no haber combinado algún estado con otro código, cuando necesito hacer "un cambio rápido".
Si tiene varios estados y no quiere saturar su componente principal, puede usar un enlace personalizado , como probablemente sepa.
Y esa es la belleza de este estilo declarativo:
No tiene que pensar demasiado en ese enlace personalizado por ahora, simplemente puede mover los estados allí tal como están.
Si luego siente que debe cambiar el nombre de algo u organizar el estado de manera diferente (pero aún siguiendo la forma de reaccionar), es fácil lanzar estados entre componentes (o ganchos, o redux, ...),