Home > OS >  Inside child component, how do I find out what the parent component is?
Inside child component, how do I find out what the parent component is?

Time:01-03

Inside a child component, I try to figure out what the parent component is. Use case: I want to apply differing CSS classes to my component, depending on the parent component.

I read about Forwarding Refs (I use function components) and thought this might be the solution, but I struggle with applying it.

My components look like this:

export let ParentA = ({ children }) => {
  return <ul data-parent-a>{children}</ul>;
};

export let ParentB = ({ children }) => {
  return <ul data-parent-b>{children}</ul>;
};

export let Child = ({ children }) => {
  return <li data-child>{children}</li>;
};

They are used like this:

<ParentA>
  <Child>Item 1</Child>
  <Child>Item 2</Child>
  <Child>Item 3</Child>
</ParentA>

<ParentB>
  <Child>Item 4</Child>
  <Child>Item 5</Child>
  <Child>Item 6</Child>
</ParentB>

With this it seems there is no way to pass the ref since I only render children. So I tried to create "private" component just to be able to pass the ref like this:

export let ParentA = React.forwardRef(({ children }, ref) => {
  return (
    <ul ref={ref} data-parent-a>
      {children}
    </ul>
  );
});

export let ParentB = React.forwardRef(({ children }, ref) => {
  return (
    <ul ref={ref} data-parent-b>
      {children}
    </ul>
  );
});

export let Child = ({ children }) => {
  const Internal = () => {
    return <li data-child>{children}</li>;
  };
  const ref = React.createRef();
  console.log(ref); // logs {current: null}
  return <Internal ref={ref} />;
};

Unfortunately, this doesn't give me any useful information whatsoever as it logs null. You can play with it here: https://codesandbox.io/s/bold-wing-3r08ii?file=/src/App.js:28-395

What do I need to do to figure out inside a child component what the parent component is?

CodePudding user response:

Essentially, you don't. The parent component needs to actively tell the child this information by passing it in props.

The most basic way is to do it yourself:

<ParentA>
   <Child isParentA />
   <Child isParentA />
</ParentA>

But you could do this by having the parents inject a prop automatically into all children. Since you are just passing down classes, you could just manipulate it such that the desired class is passed down.

export let ParentA = ({ children }) => {
  return (
    <ul data-parent-a>
      {React.Children.map(children, child => (
          React.cloneElement(child, { className: 'child-of-a'})
      ))}
    </ul>
  );
});

Now className in the props of child will be child-of-a if used within ParentA.

However, you should be aware CSS already allows you to target children natively based on the parent:

ul[data-parent-a] li[data-child] {
   // Your styles for children in A 
}

ul[data-parent-b] li[data-child] {
   // Your styles for children in b 
}

CodePudding user response:

Components shouldn't be aware of their parents. Either pass the class you need to pass explicitly, or better just rely on CSS:

function ParentA() {
  return (
    <div className="parent-a">
      <Child/>
    </div>
  );
}

function ParentB() {
  return (
    <div className="parent-b">
      <Child/>
    </div>
  );
}

function Child() {
  return (
    <div className="child">
      ...
    </div>
  );
}
.parent-a .child {
  // case parent a styles here
}
.parent-b .child {
  // case parent b styles here
}
  • Related