Search code examples
reactjstypescriptref

React - child.ref.current is null in componentdidmount


Here's many similar questions but I still couldn't solve this problem.

Child's ref is null in Listner.

I really don't understand what this is.

The code is below.

  • react 17.0.1
// Parent.tsx
const Parent: React.FC<{id: string}> = (props) => {
  const [id] = useState(props.id)  
  const modalRef = createRef<ModalRef>();

  // If I registerd the Listner here, modalRef is not null but,
  // multiple Listner has registered.

  useEffect(() => {
    listner.on('MODAL_POPUP', (o:{param:string}) => {
      modalRef.current?.pop(o.param); // <--- modalRef.current is null
    });
    return() => {};
  }, []);

  return (
    <Modal ref={modalRef} id={id}>
      <div>contents</div>
    </Modal>
  );
};
// Modal.tsx
export interface ModalProps {
  id: string;
}
export interface ModalRef {
  pop: () => void;
}

const Modal = React.forwardRef<ModalRef, ModalProps>((props, ref) => {
  const [id] = useState(props.id);

  useImperativeHandle(ref, () => ({
    pop() {
      console.log('popup modal');
    },
  }));

  return createPotal(
    <div>contents..</div>,
    document.getElementById('modal-root') as HTMLElement,
  );
});

Any advice for me? Thanks.


Solution

  • You need to use useRef for creating the ref in React Function Components, so change it to this:

    const Parent: React.FC<{id: string}> = (props) => {
      const [id] = useState(props.id)  
      const modalRef = useRef<ModalRef>(); // <== here
    
      useEffect(() => {
        listner.on('MODAL_POPUP', (o:{param:string}) => {
          modalRef.current?.pop(o.param); 
        });
        return() => {
          listner.off('MODAL_POPUP', ()=>{});
        };
      }, []);
    
      return (
        <Modal ref={modalRef} id={id}>
          <div>contents</div>
        </Modal>
      );
    };