2

I'm trying my app using material-ui lib.

I create a Table and just follow the code in Custom Table Pagination Action, but I got the error like this.

Error I got:

Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check the render method of `TablePaginationActions`.
    in TablePaginationActions (created by WithStyles(TablePaginationActions))
    in WithStyles(TablePaginationActions) (created by TablePagination)

My DataTables component:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import {
  ListItem,
  TableFooter,
  TablePagination,
  ListItemText,
  Avatar,
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableRow,
  Paper
} from '@material-ui/core';

import TablePaginationActionsWrapped from './TablePaginationActions'

const CustomTableCell = withStyles(theme => ({
  body: {
    fontSize: 14,
    paddingRight: 0,
  },
  head: {
    paddingRight: 0,
  }
}))(TableCell);

const CustomTableRow = withStyles(theme => ({
  root: {},
}))(TableRow);

const CustomTableHead = withStyles(theme => ({
  root: {
    padding: '0'
  },
}))(TableHead);

const styles = theme => ({
  root: {
    width: '100%',
    marginTop: theme.spacing.unit * 3,
    overflowX: 'auto',
    borderRadius: '0'
  },
  table: {
    minWidth: 500,
  },
  tableWrapper: {
    overflowX: 'auto',
  },
});

class DataTables extends Component {

  state = {
    data: this.props.reportsList,
    page: 0,
    rowsPerPage: 10,
  }

  handleChangePage = (event, page) => {
    this.setState({page});
  };

  handleChangeRowsPerPage = event => {
    this.setState({rowsPerPage: event.target.value});
  };

  render() {
    const {classes, reportsList} = this.props;
    const {data, rowsPerPage, page} = this.state;
    const emptyRows = rowsPerPage - Math.min(rowsPerPage, data.length - page * rowsPerPage);

    return (
      <Paper className={classes.root}>
        <div className={classes.tableWrapper}>
          <Table className={classes.table}>
            <CustomTableHead>
              <CustomTableRow>
                <CustomTableCell>ID</CustomTableCell>
                <CustomTableCell>Report Title</CustomTableCell>
                <CustomTableCell>Author</CustomTableCell>
                <CustomTableCell>Date created</CustomTableCell>
              </CustomTableRow>
            </CustomTableHead>
            <TableBody>
              {data.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map(report => {
                return (
                  <CustomTableRow key={report.id}>
                    <CustomTableCell>{report.id}</CustomTableCell>
                    <CustomTableCell component="th" scope="row">
                      {report.title}
                    </CustomTableCell>
                    <CustomTableCell padding="none" component="th" scope="row">
                      <ListItem>
                        <Avatar alt="Avatar image" src={report.userId.avatar}/>
                        <ListItemText>{report.userId.firstName}</ListItemText>
                      </ListItem>
                    </CustomTableCell>
                    <CustomTableCell component="th" scope="row">
                      {report.date}
                    </CustomTableCell>
                  </CustomTableRow>
                );
              })}
              {emptyRows > 0 && (
                <TableRow style={{ height: 48 * emptyRows }}>
                  <TableCell colSpan={6} />
                </TableRow>
              )}
            </TableBody>
            <TableFooter>
              <TableRow>
                <TablePagination
                  colSpan={3}
                  count={reportsList.length}
                  rowsPerPage={this.state.rowsPerPage}
                  page={this.state.page}
                  onChangePage={this.handleChangePage}
                  onChangeRowsPerPage={this.handleChangeRowsPerPage}
                  ActionsComponent={TablePaginationActionsWrapped}

                  // ActionsComponent={TablePaginationActionsWrapped} If not use this, my app work fine.
                />
              </TableRow>
            </TableFooter>
          </Table>
        </div>
      </Paper>
    );
  }
}

DataTables.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(DataTables);

And my TablePaginationActionsWrapped component:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import IconButton from '@material-ui/core/IconButton';
import { FirstPageIcon, KeyboardArrowLeft, KeyboardArrowRight, LastPageIcon } from '@material-ui/icons'

const actionsStyles = theme => ({
  root: {
    flexShrink: 0,
    color: theme.palette.text.secondary,
    marginLeft: theme.spacing.unit * 2.5,
  },
});

class TablePaginationActions extends Component {

  handleFirstPageButtonClick = event => {
    this.props.onChangePage(event, 0);
  };

  handleBackButtonClick = event => {
    this.props.onChangePage(event, this.props.page - 1);
  };

  handleNextButtonClick = event => {
    this.props.onChangePage(event, this.props.page + 1);
  };

  handleLastPageButtonClick = event => {
    this.props.onChangePage(
      event,
      Math.max(0, Math.ceil(this.props.count / this.props.rowsPerPage) - 1),
    );
  };

  render() {

    const { classes, count, page, rowsPerPage, theme } = this.props;

    return (
      <div className={classes.root}>
        <IconButton
          onClick={this.handleFirstPageButtonClick}
          disabled={page === 0}
          aria-label="First Page"
        >
          {theme.direction === 'rtl' ? <LastPageIcon /> : <FirstPageIcon />}
        </IconButton>
        <IconButton
          onClick={this.handleBackButtonClick}
          disabled={page === 0}
          aria-label="Previous Page"
        >
          {theme.direction === 'rtl' ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
        </IconButton>
        <IconButton
          onClick={this.handleNextButtonClick}
          disabled={page >= Math.ceil(count / rowsPerPage) - 1}
          aria-label="Next Page"
        >
          {theme.direction === 'rtl' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
        </IconButton>
        <IconButton
          onClick={this.handleLastPageButtonClick}
          disabled={page >= Math.ceil(count / rowsPerPage) - 1}
          aria-label="Last Page"
        >
          {theme.direction === 'rtl' ? <FirstPageIcon /> : <LastPageIcon />}
        </IconButton>
      </div>
    );
  }
}

TablePaginationActions.propTypes = {
  classes: PropTypes.object.isRequired,
  count: PropTypes.number.isRequired,
  onChangePage: PropTypes.func.isRequired,
  page: PropTypes.number.isRequired,
  rowsPerPage: PropTypes.number.isRequired,
  theme: PropTypes.object.isRequired,
};

const TablePaginationActionsWrapped = withStyles(actionsStyles, { withTheme: true })(
  TablePaginationActions,
);

export default TablePaginationActionsWrapped;

What did I'm wrong here. please help me.

5
  • You put "import TablePaginationActionsWrapped from './TablePaginationActions'" and in your comments you said that the file name ends with **wrapper. What is the right filename. You must have this name in the import default wrapper from '. /rightFileName' Commented Jul 27, 2018 at 4:17
  • Sorry about the format. I did the comment from the phone and I did something wrong . Commented Jul 27, 2018 at 4:26
  • @AntonioRodriguez you mean import TablePaginationActionsWrapped from './TablePaginationActions' the name and the url should be the same ? Commented Jul 27, 2018 at 4:35
  • Try console.log(classes) or other variable in your render() method. I saw you destructuring classes from props but I didn't see it set anywhere. Commented Jul 27, 2018 at 4:49
  • Not necessarily. Maybe I get confused. I will take a look more deeply. Commented Jul 27, 2018 at 5:14

1 Answer 1

2

There is only one issue. You are using wrong name for icon components. It is LastPage and FirstPage not LastPageIcon and FirstPageIcon. Just correct it, and it will work fine.

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { withStyles } from '@material-ui/core/styles'
import IconButton from '@material-ui/core/IconButton'
import { FirstPage, KeyboardArrowLeft, KeyboardArrowRight, LastPage } from '@material-ui/icons'

const actionsStyles = theme => ({
  root: {
    flexShrink: 0,
    color: theme.palette.text.secondary,
    marginLeft: theme.spacing.unit * 2.5
  }
})

class TablePaginationActions extends Component {
  handleFirstPageButtonClick = event => {
    this
      .props
      .onChangePage(event, 0)
  }

  handleBackButtonClick = event => {
    this
      .props
      .onChangePage(event, this.props.page - 1)
  }

  handleNextButtonClick = event => {
    this
      .props
      .onChangePage(event, this.props.page + 1)
  }

  handleLastPageButtonClick = event => {
    this
      .props
      .onChangePage(event, Math.max(0, Math.ceil(this.props.count / this.props.rowsPerPage) - 1))
  }

  render() {
    const { classes, count, page, rowsPerPage, theme } = this.props

    return (
      <div className={classes.root}>
        <IconButton
          onClick={this.handleFirstPageButtonClick}
          disabled={page === 0}
          aria-label='First Page'>
          {theme.direction === 'rtl'
            ? <LastPage/>
            : <FirstPage />}
        </IconButton>
        <IconButton
          onClick={this.handleBackButtonClick}
          disabled={page === 0}
          aria-label='Previous Page'>
          {theme.direction === 'rtl'
            ? <KeyboardArrowRight />
            : <KeyboardArrowLeft />}
        </IconButton>
        <IconButton
          onClick={this.handleNextButtonClick}
          disabled={page >= Math.ceil(count / rowsPerPage) - 1}
          aria-label='Next Page'>
          {theme.direction === 'rtl'
            ? <KeyboardArrowLeft />
            : <KeyboardArrowRight />}
        </IconButton>
        <IconButton
          onClick={this.handleLastPageButtonClick}
          disabled={page >= Math.ceil(count / rowsPerPage) - 1}
          aria-label='Last Page' />
      </div>
    )
  }
}

TablePaginationActions.propTypes = {
  classes: PropTypes.object.isRequired,
  count: PropTypes.number.isRequired,
  onChangePage: PropTypes.func.isRequired,
  page: PropTypes.number.isRequired,
  rowsPerPage: PropTypes.number.isRequired,
  theme: PropTypes.object.isRequired
}

export default withStyles(actionsStyles, { withTheme: true })(TablePaginationActions)

Try replacing, it should work. You can check icon name from https://material.io/tools/icons/?icon=first_page&style=baseline. You just need to use it by converting it to Capital case. Like icon first_page becomes FirstPage in @material-ui/icons.

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

Comments

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.