How can I properly determine when a conditionally rendered child component's forwardRef is initialized?
Asked Answered
T

0

0

I am working with a component which is wrapped with a ContainerLoading component which will conditionally render children with a forwardRef attached to one of the child components (TestChild) once loading is complete. When wrapped with this component, the passed ref will initially render on page load as undefined (as it hasn't been rendered yet) and will continue to remain undefined until the child is rendered.

ContainerLoading.jsx

const ContainerLoading = ({ children, loading, loadingMessage }) => {
  return (
    <>
      {loading && <>{loadingMessage && <p>{loadingMessage}</p>}</>}
      {!loading && children}
    </>
  );
};

App.jsx

export default function App() {
  const testRef = useRef();
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    console.log("Your div object", testRef.current);
  }, []);

  useEffect(() => {
    setTimeout(() => {
      setLoading(false);
    }, 1000);
  });

  return (
    <ContainerLoading loading={loading} loadingMessage={"Loading"}>
      <h1 style={{ textAlign: "center" }}>Nested Ref Demo</h1>
      <div
        style={{
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
          flexWrap: "wrap"
        }}
      >
        <TestChild ref={testRef} />
      </div>
    </ContainerLoading>
  );
}

Edit friendly-glitter-uq3r2o

I've discovered that I can utilize a useEffect with testRef.current as a dependency to determine when the ref is initialized, though I've read that this is an anti-pattern (https://mcmap.net/q/141855/-is-it-safe-to-use-ref-current-as-useeffect-39-s-dependency-when-ref-points-to-a-dom-element) and we should be utilizing a useCallback pattern to set the ref, as shown below:

const handleSetRef = useCallback((node) => {
  setRef(node);
}, []);

// Code removed for brevity

<TestChild ref={handleSetRef} />

Unfortunately this pattern doesn't seem to work due to the ContainerLoading component in combination with the TestChild component also utilizing a forwardRef. The only way I can think to get this working properly is to utilize the aforementioned anti-pattern.

Note that when changing TestChild to a div, everything works properly.

Any thoughts on how to accomplish what I need, preferably without modifying the either the TestChild or ContainerLoading components? Thanks!

Tetter answered 2/3, 2023 at 22:54 Comment(3)
Sorry but I couldn't understand whats not working or what expected from your sandbox exampleSandy
@DennisVash, essentially if I change TestChild to a div, the handleRef callback gets called automatically on page load. If I leave it as TestChild, that handleRef doesn't get called until there's a re-render. I'm trying to figure out why when the element is a child component it doesn't work, but when it's simply a div it does. Hopefully that makes sense!Tetter
Just pass the forwardedRef to the inner div, whatever you trying to do with setRefs should be handled by dedicated hook "useImperativeHandle" beta.reactjs.org/reference/react/useImperativeHandleSandy

© 2022 - 2024 — McMap. All rights reserved.