Skip to content

|React:useOutsideClick hook gives forwardRef warning message

From firebase I fetch data and map this data to be shown in cards, every card has edit component and CardComponent(edit component parent) which use ref provided from useHandleOpen custom hook

Error message:

Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

Component where ref is in use

export default function EditCard(id) {
  const { ref, isOpen, setIsOpen } = useHandleOpen(false);

  return (
    <div>
      <GoKebabVertical
        ref={ref}
        className="cursor-pointer   "
        onClick={() => setIsOpen(true)}
      />
      {isOpen && (
        <div
          ref={ref}
          className="w-20 h-15 bg-white z-30 rounded-md  absolute text-center
        top-0 right-0
        "
        >
          <p className="hover:bg-blue-300 hover:text-white cursor-pointer">
            Edytuj
          </p>
          <p
            className="bg-red-400 text-white font-semibold   hover:bg-red-600 cursor-pointer"
            onClick={() => {}}
          >
            UsuĊ„
          </p>
        </div>
      )}
    </div>
  );
}

export const Edit = memo(EditCard);

Card component which use ref tho and its Edit parent

const Card = ({ data, id }) => {
  const editRef = useRef(null);

  const { ref, isOpen, setIsOpen } = useHandleOpen(editRef);

  return (
    <div
      className="bg-gradient-to-r from-blue-200 to-purple-500
      w-64 h-28  rounded-md relative
     "
    >
      <div className="relative top-0 left-0">
        <p className="px-2 pt-1 font-bold   text-gray-800 text-lg">
          {data.subject_name}
        </p>
        <p className="px-2 text-xs   text-gray-800">Sala 101</p>
      </div>
      <div
        className="absolute top-0 right-0 rounded-r-md
        rounded-b-none
      bg-white w-6 h-7
grid place-items-center
      "
      >
        <Edit id={id} />
      </div>
      <div className="absolute bottom-9 left-0 mb-2.5">
        <p className="px-2 text-xs   text-gray-800">{data.teacher}</p>
      </div>
      <div className=" flex direction-row mt-7 text-center  w-full justify-end align-bottom pr-2    ">
        <div className="rounded-lg w-14 h-7 mx-3 bg-purple-300">
          <a
            href={data.link_subject}
            className="text-gray-800 
          
          "
            target="_blank"
            rel="noreferrer"
          >
            Lekcja
          </a>
        </div>
        <div className="rounded-lg w-14 h-7 bg-gray-800 ">
          <a
            href={data.link_online_lesson}
            target="_blank"
            rel="noreferrer"
            className="text-white"
          >
            Online
          </a>
        </div>
      </div>
      <div
        className=" absolute bottom-0 left-0 rounded-l-md
      bg-white w-7 h-6  grid place-items-center devide-solid"
      >
        {isOpen ? (
          <AiOutlineUp
            className="cursor-pointer"
            ref={ref}
            onClick={() => setIsOpen(true)}
          />
        ) : (
          <AiOutlineDown
            className="cursor-pointer"
            ref={ref}
            onClick={() => setIsOpen(true)}
          />
        )}
      </div>
      {isOpen && (
        <div
          className="bg-gradient-to-r from-blue-200 to-purple-500 w-full text-left rounded-b-md p-4 "
          ref={ref}
        >
          <p className="font-bold   text-gray-800 text-sm ">Lekcje w:</p>
          <p className="text-gray-800 text-sm">PN: 8-12</p>
        </div>
      )}
    </div>
  );
};

export const CardSubject = memo(Card);

Custom hook with ref:

    export default function useHandleOpen() {
      const [isOpen, setIsOpen] = useState(false);
      const ref = useRef(null);
    
      const handleClickOutside = (event) => {
        if (ref.current && !ref.current.contains(event.target)) {
          setIsOpen(!isOpen);
        }
      };
    
      useEffect(() => {
        document.addEventListener("click", handleClickOutside, !isOpen);
    
        return () => {
          document.removeEventListener("click", handleClickOutside, !isOpen);
        };
      });
    
      return { ref, isOpen, setIsOpen };
    }

Edit: Tried change it this way, but this displays warning too.

export default function useHandleOpen(ref) {
  const [isOpen, setIsOpen] = useState(false);

  const handleClickOutside = (event) => {
    if (ref.current && !ref.current.contains(event.target)) {
      setIsOpen(!isOpen);
    }
  };

  useEffect(() => {
    document.addEventListener("click", handleClickOutside, !isOpen);

    return () => {
      document.removeEventListener("click", handleClickOutside, !isOpen);
    };
  });

  return { ref, isOpen, setIsOpen };
}

And use hook like this:

const editRef = useRef(null);

 const { ref, isOpen, setIsOpen } = useHandleOpen(editRef);

Answer

Ok i fixed it by removing ref from places where i use onClick method for changing the state