3

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 2

2

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);

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

Comments

1

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} />
    </>
  );
};

1 Comment

It's nice to have a working example in an answere, but you should also adress what was causing the problem and how one can solve this problem. In your example you are using functional components which simply avoids the trap of not binding the function to it's instance (what i think was the problem here).

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.