2

I have 2 types of components, for example a <Promo /> and an <Announcement />

One of my components maps over a list of items and creates either promos or announcements, how can I pass an ItemElement, rather than have to repeat the mapping based on an if statement.

current implementation

import React, { Component } from 'react'
import Promo from './Promo'
import Announcement from './Announcement'

class Demo extends Component {

  render() {
    const { ItemElement } = this.props
    let items = null

    if(ItemElement === 'Promo'){

      items = this.props.items.map((p, i) => (
        <Promo item={p} />
      ))

    } else if(ItemElement === 'Announcement') {

      items = this.props.items.map((a, i) => (
        <Announcement item={a} />
      ))
    }

    return (
      { items }
    )
  }
}

desired implementation not working

import React, { Component } from 'react'
import Promo from './Promo'
import Announcement from './Announcement'

class Demo extends Component {

  render() {
    // this would be 'Promo' or 'Announcement'
    const { ItemElement } = this.props 

    let items = this.props.items.map((p, i) => (
      <ItemElement item={p} />
    ))

    return (
      { items }
    )
  }
}

This works fine if I pass in say a 'div' or 'a' or 'span' tag, but not for my own components?

3
  • 1
    This should work fine. How are you trying to render this? Commented Jan 24, 2016 at 23:59
  • 1
    Also your render() method doesn't actually return anything. You should probably have a return (<div>{this.props.items.map(...)}</div>); in there Commented Jan 25, 2016 at 0:00
  • 1
    @rossipedia sorry, it was just an example, I will update to show the full render method returning the element. Commented Jan 25, 2016 at 0:06

1 Answer 1

3

Your render() method needs to return a single element. Right now you're returning a javascript object with a single property: items. You need to contain those items in a top level element, either another Component, or a DOM element (<div> or <span> or the like).

As for passing a component in as a prop, there's no reason you shouldn't be able to do that:

class Demo extends React.Component {

  render() {
    // this would be 'Promo' or 'Announcement'
    const { ItemElement } = this.props 

    let items = this.props.items.map((p, i) => (
      <ItemElement item={p} />
    ))

    return <ul>{items}</ul>;
  }
}

class Promo extends React.Component {
  render() {
    return <li>Promo - {this.props.item}</li>; 
  }
}

class Announcement extends React.Component {
  render() {
    return <li>Announcement - {this.props.item}</li>;
  }
}

const items = [
  "foo",
  "bar"
];

ReactDOM.render(
  <Demo 
    ItemElement={Promo} // <- try changing this to {Announcement}
    items={items} 
  />,
  document.getElementById('app')
);

Here's a jsbin demonstrating: http://jsbin.com/cakumex/edit?html,js,console,output

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for that, nice work. It wasn't an issue with the render() method needing to return a single element but something unrelated. That was just an issue with me simplifying the example and leaving out the container <div /> accidentally. The tip on passing in the component as a prop rather than as a string was helpful and a better approach than passing it as a string.
To elaborate on my issue... the items were to be rendered in a swiper using the Swiper library, <Demo /> component inits Swiper on componentDidMount(). Now, at the time the component is mounted the items are strangely not shown when I pass in the component as a prop. However this issue isn't present if I just specify <Promo /> or <Announcement /> instead of the prop <ItemElement />. It is a bit strange, maybe it is somewhat slower rendering when you pass in the component as a prop... I'm not sure?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.