Bruno Henrique
Bruno Henrique

Reputation: 323

Pass a component to another inside a props array

How to pass a relative component through props to another component to render it?

For example pass to component table from app.js a props with a component button with relative calls and just call it like in code bellow? Is it possible?

Error

Element type is invalid: expected a string (for built-in components) or a >class/function (for composite components) but got: object.

In the Table.js component

import React from "react";
import { Container } from "./styles";

const Table = ({ data, columns }) => {
  return (
    <Container>
      <thead>
        <tr>
          {columns.map((header) => {
            return <th>{header.text}</th>;
          })}
        </tr>
      </thead>
      <tbody>
        {data.map((dado) => {
          return (
            <tr>
              {columns.map((column) => {
                var { Mask } = column;
                console.log(Mask);
                return (
                  <td>
                    <Mask />
                  </td>
                );
              })}
            </tr>
          );
        })}
      </tbody>
    </Container>
  );
};

export default Table;

App.js

import React from "react";
import "./styles.css";
import Table from "./Table";

export default function App() {
  const data = [
    { name: "teste", age: 30, place: "brazil", place2: "brazil" },
    { name: "teste", age: 30, place: "brazil", place2: "brazil" },
    { name: "teste", age: 30, place: "brazil", place2: "brazil" }
  ];

  const columns = [
    {
      dataField: "name",
      text: "Nome",
      Mask: (
        <button
          type="button"
          onClick={() => {
            console.log("Do Something");
          }}
        >
          {data.name}
        </button>
      )
    },
    {
      dataField: "age",
      text: "Idade",
      Mask: (
        <button
          type="button"
          onClick={() => {
            console.log("Do Something");
          }}
        >
          {data.name}
        </button>
      )
    },
    {
      dataField: "place",
      text: "Localidade",
      Mask: (
        <button
          type="button"
          onClick={() => {
            console.log("Do Something");
          }}
        >
          {data.name}
        </button>
      )
    },
    {
      dataField: "place2",
      text: "2",
      Mask: (
        <button
          type="button"
          onClick={() => {
            console.log("Do Something");
          }}
        >
          {data.name}
        </button>
      )
    }
  ];

  return (
    <div className="App">
      <Table data={data} columns={columns} />
    </div>
  );
}

Upvotes: 1

Views: 651

Answers (2)

Vasilii Kovalev
Vasilii Kovalev

Reputation: 156

<Mask /> is applicable to function or class components only, so Mask should be either a function or a class. In the example above it is a React element, not a React component.

Please, take a look at this article to understand the difference.

So in order to render it, it is just necessary to use it as a value, like this:

{columns.map((column) => {
  var { Mask } = column;
  console.log(Mask);
  return (
    <td>
      {Mask}
    </td>
  );
})}

UPDATE: I didn't fully understand the question at first. So in order to pass data to Mask, you can use an approach from another answer or turn it into a function like this:

const columns = [
  {
    dataField: "name",
    text: "Nome",
    Mask: ({ children }) => (
      <button
        type="button"
        onClick={() => {
          console.log("Do Something");
        }}
      >
        {children}
      </button>
    )
  },
  ...
];

and render it as you did in your question:

{data.map((dado) => {
  return (
    <tr>
      {columns.map((column) => {
        var { Mask, dataField } = column;
        console.log(Mask);
        return (
          <td>
            <Mask>
              {dado[dataField]}
            </Mask>
          </td>
        );
      })}
    </tr>
  );
})}

Upvotes: 1

Ketan Ramteke
Ketan Ramteke

Reputation: 10651

enter image description here

Make following changes to Table.js :

import React from "react";
// import { Container } from "./styles";

const Table = ({ data, columns }) => {
  return (
    <>
      <thead>
        <tr>
          {columns.map(header => {
            return <th>{header.text}</th>;
          })}
        </tr>
      </thead>
      <tbody>
        {data.map(dado => {
          return (
            <tr>
              {columns.map((column, index) => {
                let { Mask } = column;
                console.log(column["Mask"]);
                Mask = {
                  ...Mask,
                  props: { children: dado[Object.keys(dado)[index]] }
                };
                /*------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^
                above you can see how we can set the children props of button
                */
                return <td>{Mask}</td>;
              })}
            </tr>
          );
        })}
      </tbody>
    </>
  );
};

export default Table;

Full working example: Stackblitz

Upvotes: 1

Related Questions