Accessing child of React Fragment

96 Views Asked by At

Say I have a component that should wrap a child component and use an IntersectionObserver to monitor when the child appears on screen, and then fade it in.

I could implement something like this:

function FadeIn(props: PropsWithChildren) {
  const ref = useRef(null);
  //Fade in logic
  return <div ref={ref}>{props.children}</div>;
}

but this introduces an additional element, which may break something. I would prefer to be able to do this:

function FadeIn(props: PropsWithChildren) {
  //Fade in logic
  return <>{props.children}</>;
}

Here I use a fragment instead of a div, but fragments cant take a ref, so there's nothing I cant actually act on.

Essentially I'm looking for a non-intrusive way to implement a React wrapper Component that provides some functionality to its children, without disturbing the DOM or editing the child itself. Can this be done?

2

There are 2 best solutions below

0
Harrison On

Here's an example of Transition using React Transition Group

This implementation would look something like this: (you can still insert a ref if needed, Transition takes a ref prop.
Note that the setup is different if you're forwarding a ref

import { Transition } from "react-transition-group";

interface RightMenuProps {
  // some props
  visible: boolean; // if the item is visible
}

const RightMenu: React.FC
  <React.PropsWithChildren<RightMenuProps>
> = ({
  // some props
  visible,
  children,
}) => {
  return (
    <Transition in={visible} timeout={0} mountOnEnter>
      {transitionState => (
        <div
          className={
            `RightMenu ${transitionState}`
          }
        >
          {chiildren}
        </div>
      )}
    </Transition>
  )
}

Using the transitionState would then allow you to style it in your own preferred way

.RightMenu {
  position: relative;
  display: flex;
  flex-direction: column;
  background-color: #AAAAAA;
  width: 0;
  min-width: 0;
  overflow: hidden;
  visibility: hidden;
  transition: width 0.2s ease-in-out, min-width 0.2s ease-in-out;
  white-space: nowrap;
}

.RightMenu.entered {
  min-width: 400px;
  visibility: visible;
  border-left: 1px solid blue;
  box-sizing: border-box;
}

.RightMenu.exiting {
  visibility: visible;
}

.RightMenu.exited {
  visibility: hidden;
  width: 0;
}

The available states are defined as:

type TransitionStatus = "entering" | "entered" | "exiting" | "exited" | "unmounted"

This example uses "react-transition-group": "^4.3.0", and the types from "@types/react-transition-group": "^4.2.3"; there are likely newer versions of this package but some of this may still apply.

1
Manana Khachatryan On

You can modify the FadeIn component in this way

import React { forwardRef, PropsWithChildren } from 'react';

 function FadeIn(props: PropsWithChildren, ref: React.Ref<any>) {
  // Fade in logic
  return <div ref={ref}>{props.children}</div>;
 }

and then you can use ref to access or interact with the wrapped content

const MyComponent = () => {
  const myRef = useRef(null);

  return (
   <FadeIn ref={myRef}>
    {/* Your content goes here */}
   </FadeIn>
  );
};