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://stackoverflow.com/a/60476525/596505) 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!

cjones26
  • 3,459
  • 1
  • 34
  • 51
  • Sorry but I couldn't understand whats not working or what expected from your sandbox example – Dennis Vash Mar 06 '23 at 07:58
  • @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! – cjones26 Mar 07 '23 at 17:41
  • Just pass the forwardedRef to the inner div, whatever you trying to do with setRefs should be handled by dedicated hook "useImperativeHandle" https://beta.reactjs.org/reference/react/useImperativeHandle – Dennis Vash Mar 08 '23 at 08:16

0 Answers0