Oi, Everton! Como vai?
Vamos resolver isso. Para ter um .current.openModal igual ao que você viu, exponha métodos do componente filho para o pai usando forwardRef + useImperativeHandle. Assim, o pai chama ref.current.openModal() ou ref.current.closeModal() mesmo que o filho encapsule um <dialog> (que tem showModal/close) ou até se for outro container controlado por estado.
Por exemplo:
- Modal que usa <dialog> e expõe openModal/closeModal
- Uso no componente pai chamando ref.current.openModal()
-- Modal.tsx --
import React, { forwardRef, useImperativeHandle, useRef } from 'react';
type ModalHandle = {
openModal: () => void;
closeModal: () => void;
};
export const Modal = forwardRef<ModalHandle, { title?: string }>(
({ title = 'Titulo' }, ref) => {
const dialogRef = useRef<HTMLDialogElement | null>(null);
useImperativeHandle(ref, () => ({
openModal() {
if (dialogRef.current?.showModal) dialogRef.current.showModal();
},
closeModal() {
if (dialogRef.current?.close) dialogRef.current.close();
},
}));
return (
<dialog ref={dialogRef}>
<h2>{title}</h2>
<p>Conteudo do modal</p>
<button onClick={() => ref && (dialogRef.current?.close?.())}>Fechar</button>
</dialog>
);
}
);
-- Parent.tsx --
import React, { useRef } from 'react';
import { Modal } from './Modal';
export default function Parent() {
const modalRef = useRef<{ openModal: () => void; closeModal: () => void } | null>(null);
return (
<div>
<button onClick={() => modalRef.current?.openModal()}>Abrir modal</button>
<button onClick={() => modalRef.current?.closeModal()}>Fechar modal</button>
<Modal ref={modalRef} title="Exemplo" />
</div>
);
}
Por que funciona?
- forwardRef: permite ao pai passar ref para o filho.
- useImperativeHandle(ref, factory): define quais métodos ficam visíveis no ref.current.
- Se seu componente não usa <dialog>, exponha métodos que alteram state interno (ex.: setIsOpen(true/false)) e renderize/oculte o modal via JSX/CSS.
Alternativa sem <dialog> (controlado por estado):
-- ModalControlled.tsx --
import React, { useState, forwardRef, useImperativeHandle } from 'react';
type ModalCtrlHandle = { openModal: () => void; closeModal: () => void; };
export const ModalControlled = forwardRef<ModalCtrlHandle, {}>((_, ref) => {
const [isOpen, setIsOpen] = useState(false);
useImperativeHandle(ref, () => ({
openModal() { setIsOpen(true); },
closeModal() { setIsOpen(false); },
}));
if (!isOpen) return null;
return (
<div role="dialog" aria-modal="true" style={{ inset: 0, position: 'fixed' }}>
<div>Conteudo</div>
<button onClick={() => setIsOpen(false)}>Fechar</button>
</div>
);
});
- Exponha métodos com useImperativeHandle.
- Encapsule o detalhe interno (dialog.showModal/close ou state).
- Use o método a partir do pai via ref.current.openModal().
Espero ter ajudado. Conte com o apoio do Fórum na sua jornada. Fico à disposição.
Abraços e bons estudos!
Caso este post tenha lhe ajudado, por favor, marcar como solucionado