Pass react component as props

236,592

Solution 1

Using this.props.children is the idiomatic way to pass instantiated components to a react component

const Label = props => <span>{props.children}</span>
const Tab = props => <div>{props.children}</div>
const Page = () => <Tab><Label>Foo</Label></Tab>

When you pass a component as a parameter directly, you pass it uninstantiated and instantiate it by retrieving it from the props. This is an idiomatic way of passing down component classes which will then be instantiated by the components down the tree (e.g. if a component uses custom styles on a tag, but it wants to let the consumer choose whether that tag is a div or span):

const Label = props => <span>{props.children}</span>
const Button = props => {
    const Inner = props.inner; // Note: variable name _must_ start with a capital letter 
    return <button><Inner>Foo</Inner></button>
}
const Page = () => <Button inner={Label}/>

If what you want to do is to pass a children-like parameter as a prop, you can do that:

const Label = props => <span>{props.content}</span>
const Tab = props => <div>{props.content}</div>
const Page = () => <Tab content={<Label content='Foo' />} />

After all, properties in React are just regular JavaScript object properties and can hold any value - be it a string, function or a complex object.

Solution 2

As noted in the accepted answer - you can use the special { props.children } property. However - you can just pass a component as a prop as the title requests. I think this is cleaner sometimes as you might want to pass several components and have them render in different places. Here's the react docs with an example of how to do it:

https://reactjs.org/docs/composition-vs-inheritance.html

Make sure you are actually passing a component and not an object (this tripped me up initially).

The code is simply this:

const Parent = () => { 
  return (
    <Child  componentToPassDown={<SomeComp />}  />
  )
}
const Child = ({ componentToPassDown }) => { 
  return (
    <>
     {componentToPassDown}  
    </>
  )
}

Solution 3

By using render prop you can pass a function as a component and also share props from parent itself:

<Parent
  childComponent={(data) => <Child data={data} />}
/>
const Parent = (props) => {
  const [state, setState] = useState("Parent to child")
  return <div>{props.childComponent(state)}</div>
}

Solution 4

I had to render components conditionally, so the following helped me:

const Parent = () => { 
  return (
    <Child  componentToPassDown={<SomeComp />}  />
  )
}
const Child = ({ componentToPassDown }) => { 
  return (
    <>
     {conditionToCheck ? componentToPassDown : <div>Some other code</div>}
    </>
  )
}

Solution 5

In my case, I stacked some components (type_of_FunctionComponent) into an object like :

[
 {...,one : ComponentOne},
 {...,two : ComponentTwo}
]

then I passed it into an Animated Slider, and in the the slide Component, I did:

const PassedComponent:FunctionComponent<any> = Passed;

then use it:

<PassedComponent {...custom_props} />
Share:
236,592
Author by

chefcurry7

Updated on July 08, 2022

Comments

  • chefcurry7 11 months

    Lets say I have:

    import Statement from './Statement';
    import SchoolDetails from './SchoolDetails';
    import AuthorizedStaff from './AuthorizedStaff';
    const MultiTab = () => (
      <Tabs initialIndex={1} justify="start" className="tablisty">
        <Tab title="First Title" className="home">
          <Statement />
        </Tab>
        <Tab title="Second Title" className="check">
          <SchoolDetails />
        </Tab>
        <Tab title="Third Title" className="staff">
          <AuthorizedStaff />
        </Tab>
      </Tabs>
    );
    

    Inside the Tabs component, this.props has the properties

    +Children[3]
    className="tablist"
    justify="start"
    

    Children[0] (this.props.children) will look like

    $$typeof:
    Symbol(react.element)
    _owner:ReactCompositeComponentWrapper
    _self:null
    _shadowChildren:Object
    _source:null
    _store:Object
    key:null
    props:Object
    ref:null
    type: Tab(props, context)
    __proto__
    Object
    

    Children[0].props looks like

    +Children (one element)
    className="home"
    title="first title"
    

    Finally Children object looks like (this is what i want to pass):

    $$typeof:Symbol(react.element)
    _owner:ReactCompositeComponentWrapper
    _self:null
    _shadowChildren:undefined
    _source:null
    _store:
    key:null
    props:Object
    __proto__:Object
    **type: function Statement()**
    ref:null
    

    The question is this, if I rewrite MultiTab like this

    <Tabs initialIndex={1} justify="start" className="tablisty">
      <Tab title="First Title" className="home" pass={Statement} />
      <Tab title="Second Title" className="check" pass={SchoolDetails} />
      <Tab title="Third Title" className="staff" pass={AuthorizedStaff} />
    </Tabs>;
    

    Inside the Tabs component

    this.props.children looks the same as above.

    children[0].props looks like

    classname:"home"
    **pass: function Statement()**
    title: "First title"
    

    I want the pass property to look like. Above just prints out the Statement function.

    $$typeof:Symbol(react.element)
    _owner:ReactCompositeComponentWrapper
    _self:null
    _shadowChildren:undefined
    _source:null
    _store:
    key:null
    props:Object
    __proto__:Object
    **type: function Statement()**
    ref:null
    

    This is a weird question, but long story I'm using a library and this is what it comes down to.

  • Norfeldt
    Norfeldt about 6 years
    I know you came with a lot of good arrow function examples. But would you mind showing how the code would look like if it was separated into different files? I'm a bit confused about how to use the class and export
  • Stefan Dragnev
    Stefan Dragnev about 6 years
    Just use export const Foo = ... and then elsewhere import {Foo} from "./foo"
  • igo
    igo almost 6 years
    Hint: make sure that Inner is not inner. Otherwise doesn't work
  • NicoleZ
    NicoleZ over 2 years
    if child has a prop.how do I access that in the parent.
  • Wide Awake over 2 years
    @NicoleZ - the basic idea is to turn the question around. Ie, create the variable in the parent and pass it down to the child as a prop. If you want the child to change the variable then you need to create a function to do this in the parent and also pass that down as another prop.
  • totymedli
    totymedli over 2 years
    Basically to pass a component like <Com a="5" /> just turn it into an arrow function: () => <Com a="5" />
  • Hadi Pawar
    Hadi Pawar about 2 years
    How can i give props to componentToPassDown in the chidl method?
  • duhaime
    duhaime about 2 years
    @HadiPawar just pass the props down: <Child componentToPassDown={<SomeComp yeet={true} />} />
  • Cat Perry
    Cat Perry 12 months
    Using and iteration of React.createElement worked for me