This is my first question here after years, so pardon me if I break any forum/platform rule.
I am trying to build a CGPA CALCULATOR so I am having an issue updating a variable on user input change.
I am a beginner so my code and description may be watery. The problem is with my handleChange
method I guess, because every time I make an input (I am testing with the courseInput
for now), the app crashes with the error:
TypeError: Cannot read property 'setState' of undefined
Someone should please explain to me in details.
I have actually tried a lot Googling but nothing seems wrong with my code.
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
// this.courseInput = React.createRef();
this.state = {
courseInput: [],
courseCode: '',
courseUnit: [0],
courseGrade: [],
totalPoint: 0,
totalUnit: 0,
newCourseInput: <form>
<input onChange={this.handleChange} type="text" placeholder='COURSE CODE' value={this.courseCode} />
{/* <input type="number" placeholder='COURSE UNIT' ref={this.courseUnit} value={this.courseUnit} />
<input type="number" placeholder='COURSE GRADE' ref={this.courseGrade} value={this.courseGrade} /> */}
</form>
};
this.createAnother = this.createAnother.bind(this);
this.handleChange = this.handleChange.bind(this);
}
// THIS createAnother TAKES THE CURRENT STATE OF courseInput AND CONCATENATES IT WITH THE newCourseInput TO MAKE LIST
createAnother() {
var courseInput = this.state.courseInput.concat(this.state.newCourseInput)
this.setState({ courseInput })
}
handleChange(event) {
var updatedCourseCode = event.target.value;
this.setState({ courseInput: updatedCourseCode }, () => console.log(this.state))
}
render() {
// console.log(this);
// var courseInput = this.state.courseInput;
return(
<div>
<header className="App-header">
<p>
THIS IS A CGPA CALCULATOR
</p>
</header>
{/* MAP FUNCTION LOOPS THROUGH THE ARRAY courseInput AND PRINTS OUT THE CODE UNIT AND GRADE IN IN ORDERED LIST */}
<ol>
{this.state.courseInput.map((courseInput, index) =>
<li key={index}>{courseInput}</li>
)}
</ol>
{/* THIS TRIGGERS AN EVENT HANDLER createAnother LOCATED UP THERE */}
<button onClick={this.createAnother} >ADD ANOTHER COURSE</button>
</div>
);
}
}
export default App;
You should not store jsx elements in your state, but only the necessary data to render these elements later when needed. you also have a mistakes(you tried to assign string to an courseInput whice is array).
import React, { Component } from "react";
// import './App.css';
class App extends Component {
constructor(props) {
super(props);
// this.courseInput = React.createRef();
this.state = {
courseInput: [],
courseCode: "",
courseUnit: [0],
courseGrade: [],
totalPoint: 0,
totalUnit: 0,
};
}
// THIS createAnother TAKES THE CURRENT STATE OF courseInput AND CONCATENATES IT WITH THE newCourseInput TO MAKE LIST
createAnother = () => {
var courseInput = this.state.courseInput.concat({
id: this.state.courseInput.length,
value: "",
});
this.setState({ courseInput });
};
handleCourseChange = (value, id) => {
const newCourseInputs = [...this.state.courseInput];
console.log(newCourseInputs);
console.log(value, id);
let courseToChange = newCourseInputs.find((c) => c.id == id);
courseToChange.value = value;
this.setState({ courseInput: newCourseInputs });
};
render() {
// console.log(this);
// var courseInput = this.state.courseInput;
console.log(this.state.courseInput);
return (
<div>
<header className="App-header">
<p>THIS IS A CGPA CALCULATOR</p>
</header>
{/* MAP FUNCTION LOOPS THROUGH THE ARRAY courseInput AND PRINTS OUT THE CODE UNIT AND GRADE IN IN ORDERED LIST */}
<ol>
{this.state.courseInput.map((courseInput, index) => (
<li key={index}>
<input
onChange={(e) =>
this.handleCourseChange(e.target.value, courseInput.id)
}
type="text"
placeholder="COURSE CODE"
value={courseInput.value}
/>
</li>
))}
</ol>
{/* THIS TRIGGERS AN EVENT HANDLER createAnother LOCATED UP THERE */}
<button onClick={this.createAnother}>ADD ANOTHER COURSE</button>
</div>
);
}
}
export default App;
this code will probably work as you intended.