Guilherme Miranda
Guilherme Miranda

Reputation: 1082

React dynamic template for component

Consider the following components: ItemsDisplay has the business logic, and List and Table are just visualisations with the same interface.

class ItemsDisplay extends Component {
    componentDidMount() {
        fetch().then(items => this.setState({ items }))
    }

    remove(item) {
        // remove item from state
    }

    render() {
        return this.props.children
    }
}
const List = ({ items, onRemove }) => (
    <ul>
        {items.map(item => <li onClick="onRemove()">{item}</li>)}
    </ul>
)
const Table = ({ items, onRemove }) => (
    <table>
        {items.map(item => (
            <tr onClick="onRemove()">
                <td>{item}</td>
            </tr>
        ))}
    </table>
)

How can I use the ItemsDisplay with both of my different visualisations? Is there a pattern for that? Or I would need to create an ItemsDisplayList and another ItemsDisplayTable as well?

<ItemsDisplay>
    <List items="items from ItemsDisplay" onRemove="remove rom ItemsDisplay" />
</ItemsDisplay>

<ItemsDisplay>
    <Table items="items from ItemsDisplay" onRemove="remove rom ItemsDisplay" />
</ItemsDisplay>

Upvotes: 1

Views: 2631

Answers (2)

Palash Karia
Palash Karia

Reputation: 700

You can make this a higher order component, like so:

const itemsDisplayFactory = (BaseComponent) => {
  return class ItemsDisplay extends Component {
    componentDidMount() {
        fetch().then(items => this.setState({ items }))
    }

    remove(item) {
        // remove item from state
    }

    render() {
      return (
        <BaseComponent
          items={this.state.items}
          onRemove={this.remove}
          // anything else that you need to pass down
          {...this.props}
        />
      )
    }
  }
}

then you can do

class List extends Component {
render(){
   <ul>
    {items.map(item => <li onClick={() => onRemove(item)}>{item}</li>)}
   </ul>
  }
}


class Table extends Component {
    render(){
       <table>
          {items.map(item => (
            <tr onClick={() => onRemove(item)}>
            <td>{item}</td>
            </tr>
          ))}
        </table>
      }
    }

and compose it together like this

const ItemsDisplayList = itemsDisplayFactory(List);
const ItemsDisplayTable = itemsDisplayFactory(Table);

<ItemsDisplayList />
<ItemsDisplayTable />

Upvotes: 1

h-des
h-des

Reputation: 865

const ItemDisplayList = ({ items, onRemove, list}) => {
    if(list) {
      return(
        <ul>
          {items.map(item => <li onClick="onRemove()">{item}</li>)}
        </ul>);
    } else {
    return(
        <table>
          {items.map(item => (
            <tr onClick="onRemove()">
            <td>{item}</td>
            </tr>
          ))}
        </table>);
    }
}

Then:

<ItemsDisplay>
    <ItemDsplayList list={true} items="items from ItemsDisplay" onRemove="remove rom ItemsDisplay" />
</ItemsDisplay>

or

<ItemsDisplay>
    <ItemDsplayList list={false} items="items from ItemsDisplay" onRemove="remove rom ItemsDisplay" />
</ItemsDisplay>

Upvotes: 0

Related Questions