'Confused about how to create a ref if there is no forward ref?

There are three options, I don't know which one is the best.

//@ts-nocheck
import React, { useEffect, useRef } from "react";

export const Child = React.forwardRef((props, ref) => {
  console.log("ref: ", ref);

  // option 1
  // const divRef = ref || React.createRef();

  // option 2, it's same with option 3?
  // const _ref = useRef(null);
  // const divRef = ref || _ref;

  // option 3, one line
  const divRef = useRef(ref?.current);

  useEffect(() => {
    console.log("divRef: ", divRef.current);
  }, []);

  return <div ref={divRef}>child</div>;
});

Use Child component inside Parent component:

const Parent = () => (
  <div>
    <Child />
  </div>
);
render(<Parent />);

As you can see, the Parent component didn't create and pass ref to Child. The logic is if the Parent passed ref, use it, if not, create one in the Child component

When I run it and check the console log, all of them seem correct because I can get the divRef.

divRef:  <ref *1> HTMLDivElement {...}


Solution 1:[1]

You can easily dismiss the 1st and 3rd options:

  • 1st (createRef) would create a new ref on each render.
  • 3rd option useRef(ref?.current) doesn't support callback refs, and won't update when the ref changes, since it's passed as initial value.

So the 2nd option would allow external or internal refs, and would also support external function refs:

export const Child = React.forwardRef((props, ref) => {
  const _ref = useRef(null);
  const divRef = ref ?? _ref;

  useEffect(() => {
    console.log("divRef: ", divRef.current);
  }, []);

  return <div ref={divRef}>child</div>;
});

Solution 2:[2]

Although they are not too different and not so significant in terms of performance, I would go for Option 1 for these reasons:

  • With option 2: useRef will be invoked matter if the parent's ref has existed or not.
  • With option 3: It's not necessary to create another ref if it's already existed by reference to ref?.current again
  • Finally option 1: The right side of || basically won't' invoke if the left side is true.

Anyway, you should not use createRef inside the functional component for a few reasons.


Or I might miss something, happy to receive any opinions.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Ryan Le