Step 10
Let's refactor the App component to a class component:
import { Component } from "react";
import Output from "./Output.js";
class App extends Component {
constructor(props) {
super(props);
this.cycles = [
"11:44 PM",
"1:14 AM",
"2:44 AM",
"4:14 AM",
"5:44 AM",
"7:14 AM",
];
}
render() {
return (
<div>
<p>If you go to bed NOW, you should wake up at...</p>
<button>zzz</button>
<Output cycles={this.cycles} />
</div>
);
}
}
export default App;
Notice the alternative approach to using React.Component class is to directly import the Component class.
Let's add a method to calculate the cycles:
calcCycles() {
// get current time
let now = Date.now(); // in milliseconds
let minute = 60 * 1000; // milliseconds
let cycle = now;
// allow 14 minutes to fall sleep
cycle += 14 * minute;
// calculate 6 sleep cycles (each 90 minutes)
for (let i = 0; i < 6; i++) {
cycle += 90 * minute;
// update the sleep cycles
this.cycles[i] = new Date(cycle).toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
});
}
// print cycles for sanity check
console.log(this.cycles);
}
Now we need to attach this method to the zzz button:
<button onClick={this.calcCycles}>zzz</button>
Save the file and reload the app. Then click on zzz button. Notice you will get an error message!

The problem is related to the execution context of calcCycle. The transpiler used in React does not bind the methods to the object of class. To solve this, you can use the bind method as follows:
<button onClick={this.calcCycles.bind(this)}>zzz</button>
If you have a method that you are going to use in multiple places, then you may want to bind it to the class object once, in the class constructor:
constructor(props) {
super(props);
this.cycles = [
"11:44 PM",
"1:14 AM",
"2:44 AM",
"4:14 AM",
"5:44 AM",
"7:14 AM",
];
this.calcCycles = this.calcCycles.bind(this);
}
Another alternative is to use arrow functions for method declaration.
calcCycles = () => {
// get current time
let now = Date.now(); // in milliseconds
let minute = 60 * 1000; // milliseconds
let cycle = now;
// allow 14 minutes to fall sleep
cycle += 14 * minute;
// calculate 6 sleep cycles (each 90 minutes)
for (let i = 0; i < 6; i++) {
cycle += 90 * minute;
// update the sleep cycles
this.cycles[i] = new Date(cycle).toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
});
}
// print cycles for sanity check
console.log(this.cycles);
}
Arrow functions do not bind their own
this, instead, they inherit one from the parent scope, which is called "lexical scoping".
Once you fixed the issue, save the file, reload the app and then click on zzz again!
