Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using ref.current in React.forwardRef

Codesandbox here

I am trying to use a ref from a parent component to listen to certain ref events in the child component where the ref is attached to the child component using React.forwardRef. However, I am getting a linting complaint in my child component when I reference ref.current, stating:

Property 'current' does not exist on type 'Ref'. Property 'current' does not exist on type '(instance: HTMLDivElement) => void'

How am I supposed to reference a ref in a React.forwardRef component? Thanks.

index.tsx:

import * as React from "react";
import ReactDOM from "react-dom";

const Component = React.forwardRef<HTMLDivElement>((props, ref) => {
  React.useEffect(() => {
    const node = ref.current;
    const listen = (): void => console.log("foo");

    if (node) {
      node.addEventListener("mouseover", listen);
    }
    return () => {
      node.removeEventListener("mouseover", listen);
    };
  }, [ref]);

  return <div ref={ref}>Hello World</div>;
});

export default Component;

const App: React.FC = () => {
  const sampleRef = React.useRef<HTMLDivElement>(null);

  return <Component ref={sampleRef} />;
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
like image 401
Jimmy Avatar asked Jun 06 '20 22:06

Jimmy


People also ask

How do you ref forwardRef?

The forwardRef hooks allows React users to pass refs to child components. The ref can be created and referenced with useRef or createRef and then passed in a parent component. Using forwardRef instead of useRef is useful when a ref needs to be accessed in a parent component.

How will you access current value of a reference in React?

Accessing Refsconst node = this.myRef.current; The value of the ref differs depending on the type of the node: When the ref attribute is used on an HTML element, the ref created in the constructor with React.createRef() receives the underlying DOM element as its current property.

What is ref and forwardRef?

The forwardRef method in React allows parent components to move down (or “forward”) refs to their children. ForwardRef gives a child component a reference to a DOM entity created by its parent component in React. This helps the child to read and modify the element from any location where it is used.

What is ref current in React?

Refs is the shorthand used for references in React. It is similar to keys in React. It is an attribute which makes it possible to store a reference to particular DOM nodes or React elements. It provides a way to access React DOM nodes or React elements and how to interact with it.


1 Answers

Refs are not necessarily objects with a current property. They can also be functions. So the type error is pointing out that you might be passed one of the latter. You'll need to write your code so that it can work with both variations.

This can be a bit tricky, but it's doable. Our effect can't piggy back on the function that was passed in, since that function could be doing literally anything, and wasn't written with our useEffect in mind. So we'll need to create our own ref, which i'll call myRef.

At this point there are now two refs: the one passed in, and the local one we made. To populate both of them, we'll need to use the function form of refs ourselves, and in that function we can assign the div element to both refs:

const Component = React.forwardRef<HTMLDivElement>((props, ref) => {
  const myRef = useRef<HTMLDivElement>(null);
  React.useEffect(() => {
    const node = myRef.current;
    const listen = (): void => console.log("foo");

    if (node) {
      node.addEventListener("mouseover", listen);
    }
    return () => {
      node.removeEventListener("mouseover", listen);
    };
  }, [ref]);

  return (
    <div ref={(node) => {
      myRef.current = node;
      if (typeof ref === 'function') {
        ref(node);
      } else if (ref) {
        (ref as MutableRefObject<HTMLDivElement>).current = node;
      }
    }}>Hello World</div>
  );
});

The reason i needed to do a type assertion of (ref as MutableRefObject<HTMLDivElement>) is that the ref object we're passed in is of type RefObject, instead of MutableRefObject. As a result, .current is readonly. In reality, .current does get changed at runtime, but it's usually React that does so. The readonly type makes sense for the normal code people write when developing a react app, but yours is not a normal case.

like image 115
Nicholas Tower Avatar answered Sep 24 '22 21:09

Nicholas Tower