stone rock
stone rock

Reputation: 1953

How to return multiple components in render function?

I have made 3 components Batcomponent, Bowlcomponent, Fieldcomponent. I am passing props to each of these components. When the string matches to bat or field or bowl that particular component is rendered and shown on web page. I am returning {renderData} inside return().

Code:

render(){

if(this.props.type === "bat"){
 renderData = (<Batcomponent 
    prop1 = this.props.type.name
    prop2 = this.props.matches
    prop3 = this.props.email
    />)
}else if(this.props.type === "bowl"){
  renderData = (<Bowlcomponent 
    prop1 = this.props.type.name
    prop2 = this.props.matches
    prop3 = this.props.email
    />)
}else if(this.props.type === "field"){
    renderData = (<Fieldcomponent 
    prop1 = this.props.type.name
    prop2 = this.props.matches
    prop3 = this.props.email
    />)
}

}

return(){
    <div>
       {renderData}
    </div>
}

Now I want to add Piechart component inside renderData. What I tried:

render(){

if(this.props.type === "bat"){
 renderData = (<Batcomponent 
    prop1 = this.props.type.name
    prop2 = this.props.matches
    prop3 = this.props.email
    />
    <Pie prop1 = this.props.type.name />
    )
}else if(this.props.type === "bowl"){
  renderData = (<Bowlcomponent 
    prop1 = this.props.type.name
    prop2 = this.props.matches
    prop3 = this.props.email
    />
    <Pie prop1 = this.props.type.name/>
    )
}else if(this.props.type === "field"){
    renderData = (<Fieldcomponent 
    prop1 = this.props.type.name
    prop2 = this.props.matches
    prop3 = this.props.email
    />
    <Pie prop1 = this.props.type.name/>
    )
}

}

return(){
    <div>
       {renderData}
    </div>
}

Above code does not work how can I add additional components inside renderData ?

If I do renderData = (<FirstComponent />) it works but if I do like this -> renderData = (<FirstComponent /> <SecondComponent/>) it does not work why ?

Upvotes: 0

Views: 848

Answers (4)

Lafi
Lafi

Reputation: 1342

here is a clean exp using the children prop:

const CompA = ({ children }) => {
  return (
    <div>
      <h3>Im component A</h3>
      {children}
    </div>
  );
};

see the codesandbox exp.

Upvotes: 1

Denis Tsoi
Denis Tsoi

Reputation: 10414

...

renderData = (
  <div>
     <Fieldcomponent 
     prop1 = this.props.type.name
     prop2 = this.props.matches
     prop3 = this.props.email
     />
     <Pie prop1 = this.props.type.name/>
  </div>
)

JSX expects components to be wrapped in a div / fragment, even internal components that you have defined in a variable/function call.

Depending on your react version, you could use Fragment or <>.

This can alternatively be done with Fragments

renderData = (
  <Fragment>
     <Fieldcomponent 
     prop1 = this.props.type.name
     prop2 = this.props.matches
     prop3 = this.props.email
     />
     <Pie prop1 = this.props.type.name/>
  </Fragment>
)

However, I'd probably recommend cleaning the code further...

render(){
  return(
    <div>
    { 
      this.props.type === 'bat' ? <Bat {...props} /> :
      this.props.type === 'bowl' ? <Bowl {...props} /> :
      this.props.type === 'field' ? <Field {...props} /> : <Default {...props} />
    }
    </div>
  )
}

Upvotes: 2

Juorder Gonzalez
Juorder Gonzalez

Reputation: 1652

The best way you can handle this is by making a kind of hash table (Just an object containing multiple components) in that way will scale as much as you want, so it could be something like

const components = {
  bat: BatComponent,
  bowl: BowlComponent,
  field: FieldComponent
}

Now make a function that will choose the right component to show

renderComponent(){
  const { type, ...restProps } = this.props;
  const Component = components[type]
  return <Component {...restProps } />
}

Now in your render function

render(){
  return {this.renderComponent()}
}

If you need to return 2 components maybe it would be better to wrap those 2 components into one and add it to the object that contains the components (hash table)

Upvotes: 2

Paul
Paul

Reputation: 857

This code does not work because adjacent JSX elements must be wrapped in an enclosing tag.

React 16 introduced Fragments, which let you wrap JSX expressions without adding an extra div.

If you're using React 16, use Fragments:

 if (this.props.type === "bat") {
      renderData = (
        <React.Fragment>
          <Batcomponent
          prop1={this.props.type.name}
          prop2={this.props.matches}
          prop3={this.props.email}
        />
        <Pie prop1={this.props.type.name}/>
        </React.Fragment>
    )
   }else if ...

If you aren't using React 16, wrap them in a div instead:

 if (this.props.type === "bat") {
      renderData = (
        <div>
          <Batcomponent
          prop1={this.props.type.name}
          prop2={this.props.matches}
          prop3={this.props.email}
        />
        <Pie prop1={this.props.type.name}/>
        </div>
    )
   }else if ...

Upvotes: 2

Related Questions