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!