Reputation: 79
I am very confused, because when I fill this.state.seats by values, it correctly render all components in DOM. But when I click on that component (button), it returns back to App.js and shows me:
Uncaught TypeError: Cannot read property 'state' of undefined
even though, the components from this state property are displayed in DOM!
Please, does anyone know what happens?
App.js
import React, { Component } from "react";
import "./App.css";
import Seats from "./Seats";
class App extends Component {
state = {
seats: this.initializeSeats()
};
initializeSeats() {
let seats = [];
let count = 5;
for (let a = 0; a < count; a++) {
for (let b = 0; b < count; b++) {
seats.push({ key: '' + a + b, reserved: false });
}
}
seats.find(s => s.key === '00').reserved = true;
return seats;
}
onClickSeat(e) {
const seats = [...this.state.seats];
let seat = seats.find(s => s.key === e.target.value);
seat.reserved = !seat.reserved;
console.log(seat.reserved);
this.setState({ seats: seats });
}
render() {
return (
<div>
<h3>Kinosál</h3>
<Seats
seats={this.state.seats}
onClickSeat={this.onClickSeat}
/>
</div>
);
}
}
export default App;
Seats.jsx
import React, { Component } from "react";
import Seat from "./Seat";
class Seats extends Component {
render() {
const result = [];
for (let seat of this.props.seats) {
if (!seat.reserved) {
result.push({ key: seat.key, reserved: seat.reserved });
}
}
return (
<div>
{result.map(seat => (
<Seat
key={seat.key}
onClick={this.props.onClickSeat}
seat={seat}
/>
))}
</div>
);
}
}
export default Seats;
Seat.jsx
import React, { Component } from "react";
import uuid from 'uuid';
class Seat extends Component {
render() {
const { seat, onClick } = this.props;
return (
<div>
<button onClick={onClick} key={uuid.v4()} value={seat.key}>{seat.key}</button>
</div>
);
}
}
export default Seat;
Upvotes: 0
Views: 402
Reputation: 319
take a look at https://reactjs.org/docs/handling-events.html
You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.
You have to bind onClickSeat
to the App
class instance of this
you can use the class arrow syntax below to do so.
onClickSeat = (e) => {
const seats = [...this.state.seats];
let seat = seats.find(s => s.key === e.target.value);
seat.reserved = !seat.reserved;
console.log(seat.reserved);
this.setState({ seats: seats });
}
Once you do that, everything should work! It also explains why you can see the components in the DOM, but onClickSeat
has its state undefined (it's because this
in onClickSeat
is NOT referring to the class instance as you were expecting)
Upvotes: 1