Navigate to next page on Table row click in React JS

Viewed 1889

I have a table where I display a list of data. On row click, I want to navigate the user to the next page. Following is my code:

export default class Venues extends Component {

  constructor(props) {
    super(props);
    this.state = {
      venues: [],
      isLoading: false,
    }
  }

  componentDidMount() {
    this.setState({isLoading:true});
    this.getVenueList();
  }

  getVenueList() {
    ApiService.getData(apiConfig.GET_VENUES, {
    }).then((res) => {
        if (res.data && res.data.error == null) {
            console.log(res.data);
            this.setState({ venues: res.data.result, isLoading: false });
            console.log(this.state.venues);
            console.log("venues");
        } else {
            alert(res.data.error.description );
        }
    });
  }
  
  handleRowClick() {
    this.props.history.push('/projectList');
  }

  addVenue() {
    this.props.history.push('/add_venue');
}

  render() {
    return (
      <div className="col-md-6 offset-md-3">
        <Form onSubmit={this.onSubmit}>
          <div className="form-group">
            <div style={divStyle}>
            <Typography variant="h4" style={style}>Venues</Typography>
                <div style={{
                    display: 'flex',
                    justifyContent: 'flex-end',
                    marginRight: '20px'
                }}> 
                <Button color="primary" onClick={() => this.addVenue()}>
                        Add Venue
                </Button></div>
              {this.state.isLoading ? (<div style={{
                    display: 'flex',
                    justifyContent: 'center',
                    alignItems: 'center',
                    height: '100vh'
                }}><div className="spinner-border text-primary" role="status" >
                        <span className="sr-only">Loading...</span>
                    </div></div>) : (
                        <Table>
                            <TableHead>
                                <TableRow>
                                    <TableCell>S.No.</TableCell>
                                    <TableCell align="center">Venue Name</TableCell>
                                    <TableCell align="center">Role</TableCell>
                                </TableRow>
                            </TableHead>
                            <TableBody>
                                {this.state.venues.map(row => (
                                    <TableRow key={row.id} onClick={this.handleRowClick}>
                                        <TableCell component="th" scope="row">
                                            {this.state.venues.indexOf(row) + 1}
                                        </TableCell>
                                        <TableCell align="center">{row.venueName}</TableCell>
                                        <TableCell align="center">{row.venueAddress}</TableCell>
                                 </TableRow>
                                ))}
                            </TableBody>
                        </Table>
                    )}
            </div>
          </div>
        </Form>
      </div>
    );
  }
}

I am getting the following error on row click:

TypeError: Cannot read property 'props' of undefined I am getting this error on handleRowClick() function.

Can someone please help me with this?

2 Answers

You need to bind your handler to the class instance scope.

Option 1: Declare the function like using arrow syntax, since the value of this inside an arrow function is always inherited from the enclosing scope.

https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/

handleRowClick = () => {
        this.props.history.push('/projectList');
    }

Option 2 Explicitly bind the handler function's scope in the constructor.

constructor(props) {
        super(props);
        this.state = {
            venues: [],
            isLoading: false,
        }
        this.handleRowClick = this.handleRowClick.bind(this);

    }

i wrote sample code this .

TableDialog.js

import React from "react";
import "./styles.css";
import {
  Table,
  TableHead,
  TableRow,
  TableCell,
  TableBody
} from "@material-ui/core";

const TableDialog = (props) => {
  const venues = [
    { id: 1, venueName: "name1", venueAddress: "add1" },
    { id: 2, venueName: "name2", venueAddress: "add2" },
    { id: 3, venueName: "name3", venueAddress: "add3" }
  ];
  const handleRowClick = () => {
    props.history.push("/tableDetail");
  };
  return (
    <div className="App">
      <Table>
        <TableHead>
          <TableRow>
            <TableCell>S.No.</TableCell>
            <TableCell align="center">Venue Name</TableCell>
            <TableCell align="center">Role</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {venues.map((row) => (
            <TableRow key={row.id} onClick={handleRowClick}>
              <TableCell component="th" scope="row">
                {venues.indexOf(row) + 1}
              </TableCell>
              <TableCell align="center">{row.venueName}</TableCell>
              <TableCell align="center">{row.venueAddress}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </div>
  );
};
export default TableDialog;

Home.js

import React from "react";
import TableDialog from "./TableDialog";

const Home = (props) => {
  console.log(props);
  return (
    <>
      <TableDialog {...props} />
    </>
  );
};

export default Home;

App.js

import React from "react";
import "./styles.css";
import Home from "./Home";
import TableDetail from "./TableDetail";
import { BrowserRouter, Switch, Route } from "react-router-dom";

export default function App() {
  return (
    <div className="App">
      <BrowserRouter>
        <Switch>
          <Route path="/tableDetail" component={TableDetail}></Route>
          <Route path="/" component={Home}></Route>
        </Switch>
      </BrowserRouter>
    </div>
  );
}

Work Demo

CodeSandbox

Notable cases
use a attribute component in Route

          <Route path="/tableDetail" component={TableDetail}></Route>
          <Route path="/" component={Home}></Route>

and second
pass props to child component.

const Home = (props) => {
  console.log(props);
  return (
    <>
      <TableDialog {...props} />
    </>
  );
};
Related