4

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 {...}
Lin Du
  • 88,126
  • 95
  • 281
  • 483

2 Answers2

2

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>;
});
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
  • Can you please elaborate on *"the 3rd option `useRef(ref?.current)` doesn't support function refs."* - why does it not support them? It's hard to find documentation on this because so many of the React docs for refs are out of date or talk as if only one type of ref exists – user56reinstatemonica8 Apr 29 '22 at 11:14
  • I presume when you say "function refs" you mean what the docs call ["callback refs"](https://reactjs.org/docs/refs-and-the-dom.html#callback-refs)? I imagine a lot of `useRef`-based logic that expects a `ref.current` will already not support these? – user56reinstatemonica8 Apr 29 '22 at 11:18
  • 1
    Callback refs indeed. I've updated the answer. Good libraries would support both. You just need to check if the ref is a function, and call the function with the value, instead of assigning it to current. – Ori Drori Apr 29 '22 at 12:11
1

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.

Ryan Le
  • 7,708
  • 1
  • 13
  • 23