Nate Thompson
Nate Thompson

Reputation: 405

Pass a parameter to a prop that is actually a component?

My scenario is that I have a table that is generated based on data. In one of the columns I would like to pass in a 'remove' button/component, which is meant to remove the row that it is in.
My issue is that the 'remove' button component needs to be given the row so it can determine which data to remove.

If you look in Table.js, you can see where I render the prop as a component '{col.component}' - But how can I also pass values to the components action?

Examples below.


App.js

import React, { Component } from 'react';
import Table from './Table';
import Table from './RemoveButton';

class App extends Component {

  //Data is the array of objects to be placed into the table
  let data = [
  {
    name: 'Sabrina',
    age: '6',
    sex: 'Female',
    breed: 'Staffordshire'
  },
  {
    name: 'Max',
    age: '2',
    sex: 'Male',
    breed: 'Boxer'
  }
  ]

  removeRow = name => {
    //Remove object from data that contains name
  }

  render() {

   //Columns defines table headings and properties to be placed into the body
   let columns = [
   {
      heading: 'Name',
      property: 'name'
   },
   {
      heading: 'Age',
      property: 'age'
   },
   {
      heading: 'Sex',
      property: 'sex'
   },
   {
      heading: 'Breed',
      property: 'breed'
   },
   {
      heading: '',
      component: <RemoveButton action=removeRow()/>
   }
   ]

    return (
      <>
        <Table
          columns={columns}
          data={data}
          propertyAsKey='name' //The data property to be used as a unique key
        />
      </>
    );
  }
}

export default App;



RemoveButton.js

import React from 'react';

const RemoveButton = action => {
    return(
        <button onClick={action}>Remove Row</button>
    )
}

export default RemoveButton;


Table.js

const Table = ({ columns, data, propertyAsKey }) =>
    <table className='table'>
        <thead>
            <tr>{columns.map(col => <th key={`header-${col.heading}`}>{col.heading}</th>)}</tr>
        </thead>
        <tbody>
            {data.map(item =>
                <tr key={`${item[propertyAsKey]}-row`}>
                    {columns.map(col => {
                       if(col.component){
                          return(<td> key={`remove-${col.property}`}>{col.component}</td>)
                       } else {
                           return(<td key={`${item[propertyAsKey]}-${col.property}`}>{item[col.property]}</td>)
                       }
                    })}
                </tr>
            )}
        </tbody>
    </table>

Upvotes: 1

Views: 141

Answers (1)

Tholle
Tholle

Reputation: 112917

Instead of passing down a component in the column, you could pass down the removeRow function to the Table component as a regular prop, and have another value on the remove column to indicate when you should render the remove button for that column, and pass the item name when you invoke it.

class App extends React.Component {
  state = {
    data: [
      {
        name: "Sabrina",
        age: "6",
        sex: "Female",
        breed: "Staffordshire"
      },
      {
        name: "Max",
        age: "2",
        sex: "Male",
        breed: "Boxer"
      }
    ]
  };

  removeRow = name => {
    this.setState(({ data }) => ({
      data: data.filter(el => el.name !== name)
    }));
  };

  render() {
    let columns = [
      {
        heading: "Name",
        property: "name"
      },
      {
        heading: "Age",
        property: "age"
      },
      {
        heading: "Sex",
        property: "sex"
      },
      {
        heading: "Breed",
        property: "breed"
      },
      {
        heading: "",
        removeCol: true
      }
    ];

    return (
      <Table
        columns={columns}
        data={this.state.data}
        removeRow={this.removeRow}
        propertyAsKey="name"
      />
    );
  }
}

const Table = ({ columns, data, removeRow, propertyAsKey }) => (
  <table className="table">
    <thead>
      <tr>
        {columns.map(col => (
          <th key={`header-${col.heading}`}>{col.heading}</th>
        ))}
      </tr>
    </thead>
    <tbody>
      {data.map(item => (
        <tr key={`${item[propertyAsKey]}-row`}>
          {columns.map(col => {
            if (col.removeCol) {
              return (
                <td key={`remove-${col.property}`}>
                  <button onClick={() => removeRow(item.name)}>
                    Remove Row
                  </button>
                </td>
              );
            } else {
              return (
                <td key={`${item[propertyAsKey]}-${col.property}`}>
                  {item[col.property]}
                </td>
              );
            }
          })}
        </tr>
      ))}
    </tbody>
  </table>
);

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>

Upvotes: 1

Related Questions