Home > OS >  useRef hook with typescript doen`t work. All was fine in jsx
useRef hook with typescript doen`t work. All was fine in jsx

Time:08-25

So I have a copy of working code , and I was trying to adapt it for typescript. I have a modal window , that I want to close if I click on anything but not modal window itself. Again - in jsx it was legit functioning code , but with typescript I have numerous errors. First of them is: Type 'MutableRefObject<HTMLButtonElement | null>' is not assignable to type 'LegacyRef<HTMLDivElement> | undefined'. Type 'MutableRefObject<HTMLButtonElement | null>' is not assignable to type 'RefObject<HTMLDivElement>'. Types of property 'current' are incompatible. Type 'HTMLButtonElement | null' is not assignable to type 'HTMLDivElement | null'. Property 'align' is missing in type 'HTMLButtonElement' but required in type 'HTMLDivElement'

import { useEffect, useRef } from 'react';
import './ModalforSelect.scss';

type Props = {
  options: string[][];
  setClick: React.Dispatch<React.SetStateAction<boolean>>;
};

export const ModalforSelect: React.FC<Props> = ({ options, setClick }) => {
  const modal = useRef<HTMLButtonElement | null>(null);

  useEffect(() => {
    const closeHandle = (event: MouseEvent) => {
      if (modal !== null) {
        if (!modal.current?.contains(event.target as HTMLInputElement)) {
          setClick(false);
        }
      }
    };

    document.addEventListener('mousedown', closeHandle);

    return () => document.removeEventListener('mousedown', closeHandle);
  }, []);

  console.log(modal.current);

  return (
    <div
      ref={modal}
      className="Select__modal"
    >
      {
        options.map(el => {
          return (
            <h3 className="Select__modalOption" key={el[1]}>
              {el[1]}
            </h3>
          );
        })
      }
    </div>
  );
};

So, I decided that maybe problem was in useEffect , so I commented out some of it functionality, but now there is another mistake that doesn't make any sence to me: Type 'MutableRefObject<HTMLButtonElement | null>' is not assignable to type 'LegacyRef<HTMLDivElement> | undefined'. Type 'MutableRefObject<HTMLButtonElement | null>' is not assignable to type 'RefObject<HTMLDivElement>'. Types of property 'current' are incompatible. Type 'HTMLButtonElement | null' is not assignable to type 'HTMLDivElement | null'. Property 'align' is missing in type 'HTMLButtonElement' but required in type 'HTMLDivElement'

import { useRef } from 'react';
import './ModalforSelect.scss';

type Props = {
  options: string[][];
};

export const ModalforSelect: React.FC<Props> = ({ options }) => {
  const modal = useRef<HTMLButtonElement | null>(null);

  console.log(modal.current);

  return (
    <div
      ref={modal}
      className="Select__modal"
    >
      {
        options.map(el => {
          return (
            <h3 className="Select__modalOption" key={el[1]}>
              {el[1]}
            </h3>
          );
        })
      }
    </div>
  );
};

Will be glad for any advice.

CodePudding user response:

You're trying to use a ref for a <button> (HTMLButtonElement) element for a div.

The correct type is

const modal = useRef<HTMLDivElement>(null);

Also, unless you really want to accept the children prop, don't use React.FC; a plain function is enough.

import React, { useRef } from "react";

type Props = {
  options: string[][];
};

export function ModalforSelect({ options }: Props) {
  const modal = useRef<HTMLDivElement>(null);
  return (
    <div ref={modal} className="Select__modal">
      {options.map((el) => {
        return (
          <h3 className="Select__modalOption" key={el[1]}>
            {el[1]}
          </h3>
        );
      })}
    </div>
  );
}
  • Related