2

I have looked through other peoples questions relating to this but cant find a suitable answer. I would like to pass children to a component and then pull out the specific children where I want them, most examples I have seen just have the children render in the same place.

My component looks something like this -

<ParentComponent>

<ChildOne/>
<ChildTwo/>

<ParentComponent/>

When I log the props.children inside the parent component I get an array which contains both children as objects. is there a simple way to pull out the specific child where I need it such as {props.children.ChildOne} at the moment I am using props.children[0] which isn't ideal as we will be passing the children dynamically in the future and the array length may change.

As always any help is greatly appreciated!

jjlittle
  • 47
  • 1
  • 8
  • You have a ton of elements here, to check the type of a child element: https://stackoverflow.com/questions/27366077/only-allow-children-of-a-specific-type-in-a-react-component – Drarig29 Nov 11 '21 at 09:43
  • Apparently, you need to use [`React.Children`](https://reactjs.org/docs/react-api.html#reactchildren) and the comparison `child.type === ().type` or `child.type === ChildOne`. – Drarig29 Nov 11 '21 at 09:48
  • All of which seems to be production ready (works after minimisation). – Drarig29 Nov 11 '21 at 09:49

5 Answers5

1

Depending on your exact situation and needs, it might make more sense to pass child components as props than using the special children prop. Then you can render them whichever way you like.

<ParentComponent childOne={ChildOne} childTwo={ChildTwo} />
...
const ParentComponent = ({ childOne, childTwo }) => {
  return (
    <div>
      {childOne}
      <div>
        {childTwo}
      </div>
    </div>
  );
};

But knowing your exact scenario would help a lot with conceptualising the best way to implement this. Perhaps you can refactor your code to avoid passing an array of children like this.

szaman
  • 2,159
  • 1
  • 14
  • 30
1

You should define the displayName property for the child components and then use the displayName in the parent to find the specific children from children list and place them where you want it to be.

// define displayName for each component, it can be any string
// You can set the displayName for any react component before exporting as shown 
// below

const ChildOne = (props) => { return (<div> Child One </div>)}
ChildOne.displayName = "ChildOne";
export default ChildOne;

const ChildTwo = (props) => { return (<div> Child Two </div>)}
ChildTwo.displayName = "ChildTwo";
export default ChildTwo;

Now in parent component you can filter out the specific child by using their displayName.

const ParentComponent = (props) => {

const getChildByDisplayName = (displayName) => {
  const child = React.Children.map(props.children, (child => {
     // you can access displayName property by child.type.displayName
     if (child.type.displayName === displayName) return child;
     return null;
  }))
  return child;
}    

return (
 <div>
   {/* You can change the order here as per your wish*/}
   {getChildByDisplayName("ChildOne")}
   {getChildByDisplayName("ChildTwo")}
 </div>
)
}

That's it, Now even if you put ChildTwo before ChildOne like below example, parent component will still render the ChildOne first and then ChildTwo because we have defined order in parent.

<ParentComponent>

 <ChildTwo/>
 <ChildOne/>

<ParentComponent/>
djsdev
  • 76
  • 2
  • 4
0

Actually, the ReactChildren API I was mentioning is useless here.

You can do something like this instead:

import React from 'react';
import { ChildOne } from './YourFile';

export function ParentComponent({children}) {
  return children.find(child => child.type === ChildOne)
}
Drarig29
  • 1,902
  • 1
  • 19
  • 42
0

Using the key seems simpler:

whatever is using the parent component:

<ParentComponent>
    <ChildOne key="title"/>
    <ChildTwo key="picture"/>
<ParentComponent/>

parent component:

export default function ParentComponent(props: any) {
    const title = props.children.find((o: any) => o.key === 'title')
    const picture = props.children.find((o: any) => o.key === 'picture')
    return <div>
        <jumbobox>
            {title}
        </jumbobox>
        <fancyframe>
            {picture}
        </fancyframe>
    </div>
}
toddmo
  • 20,682
  • 14
  • 97
  • 107
-1

One way is to control the Child Components being passed to ParentComponent through state/props/redux store management in the component containing ParentComponent and its children.

But to have the solution as per your use case, we can avoid using children prop and use our defined prop on ParentComponent.

<ParentComponent
    components={[
     {key: 1, component: <div>Hello</div>}
    ]}
/>

So, we can now filter from the key.

Checkout this demo

Neetigya Chahar
  • 683
  • 5
  • 14