Zak Kus
Zak Kus

Reputation: 1513

How to pass optional elements to a component as a prop in reactjs

I am trying to figure out the proper "react" way to pass in an optional prop that is an Element to a container component, that is handled differently from the children of that component.

For a simple example, I have a Panel component, which renders its children, that also has an optional "title" prop (which is an element rather than a string, for the sake of the example) that gets specially rendered (put in a special spot, with special behaviors in while maintaining the abstraction.

One option is to have a component which is pulled out of the children and rendered specially:

<Panel>
   <Title> some stuff</Title>
   <div> some other stuff</div>
</Panel>

But it seems wierd to have the children pulled out and handled separately like that.

How is this normally handled in react, and am I even thinking about this the right way

Upvotes: 18

Views: 55547

Answers (4)

Taiwosam
Taiwosam

Reputation: 549

One thing you can do is have default props (usually initialised to a no-op) for your component.

For example, if you want to have an optional function prop:

class NewComponent extends React.Component {
    ...
    componentDidMount() {
        this.props.functionThatDoesSomething()
    }
}

NewComponent.defaultProps = {
    functionThatDoesSomething: () => {}
}

This way, parent components can choose to pass the function prop or not and your app won't crash due to the error

this.props.functionThatDoesSomething is not a function .

Upvotes: 0

Franco M&#233;ndez
Franco M&#233;ndez

Reputation: 79

When you need an attribute from your optional prop, you will have to check first if the prop was delivered. Otherwise, you will get a:

TypeError: Cannot read property 'yourPropProperty' of undefined

In conditional rendering context (depending on my optional this.props.ignore array), this won't work:

{!this.props.ignore.includes('div')) && (
   <div>
      Hey
   </div>
)}

Instead, you should do:

{(!this.props.ignore || !this.props.ignore.includes('div'))) && (
   <div>
      Hey
   </div>
)}

Upvotes: 1

John Ruddell
John Ruddell

Reputation: 25842

you can do something like this

render(){
    <div>
        {this.props.title ? this.props.title : null}
        {this.props.children}
    </div>
}

basically if you pass a title element as a prop then create it as an element and render it. else just put in null...

to create it you would do something like this.

<Panel title={<Title>Something Here</Title>}
    <div> something here</div>
</Panel>

This is generally how react should handle optional child components

Upvotes: 5

Jordan Running
Jordan Running

Reputation: 106027

You don't need to do anything special. Just pass the title component as a prop, and then use {this.props.title} wherever you want it to be rendered:

class Panel extends React.Component {
  render() {
    return <div>
      {this.props.title}
      <div>Some other stuff...</div>
    </div>;
  }
}

class App extends React.Component {
  render() {
    var title = <Title>My Title</Title>;
    return <Panel title={title}/>;
  }
}

If you don't pass any value for the title prop (or if the value is false, null, or undefined) then nothing will be rendered there.

This is a fairly common pattern in React.

Upvotes: 18

Related Questions