chefcurry7
chefcurry7

Reputation: 5241

Pass react component as props

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.

Upvotes: 200

Views: 356604

Answers (7)

Skar
Skar

Reputation: 642

Most common way to pass a component as a prop is this:

 function ParentComponent(props) {
  return (
    <div>
      {props.childComponent}
    </div>
  );
}

function ChildComponent() {
  return (
    <div>
      This is the child component.
    </div>
  );
}

function App() {
  return (
    <ParentComponent childComponent={<ChildComponent />} />
  );
}

If child component is for example a button and it has some state with it, it will pass automatically and work.

Upvotes: 1

Mossen
Mossen

Reputation: 604

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>
}

Upvotes: 14

Luis Pereira
Luis Pereira

Reputation: 340

How about using "React.createElement(component, props)" from React package

const showModalScrollable = (component, props) => {
 Navigation.showModal({
   component: {
     name: COMPONENT_NAMES.modalScrollable,
     passProps: {
        renderContent: (componentId) => {
          const allProps = { componentId, ...props };

          return React.createElement(component, allProps);
    },
  },
},

}); };

Upvotes: 1

Hatim
Hatim

Reputation: 447

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>}
    </>
  )
}

Upvotes: 6

kimo_ouz
kimo_ouz

Reputation: 389

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} />

Upvotes: 3

Wide Awake
Wide Awake

Reputation: 1469

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}  
    </>
  )
}

Upvotes: 115

Stefan Dragnev
Stefan Dragnev

Reputation: 14473

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.

Upvotes: 236

Related Questions