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
}