'how to solve "TypeError: Cannot read properties of undefined (reading 'state') at checkGuess (Flashcard.js:34:1)" when trying to post form data?
I have a simple react flashcard app that sends data to the backend about the flashcard including the question, answer choices, and the answer that the user guessed along with the correct answer. I am trying to post the user's name that they enter into the form to the same backend route as the other data. I have successfully made the form and on submit the program alerts the user that they've entered their username and it displays the username. that works perfectly. Now I'm trying to get that value that was entered for the username and post it to the backend in the same function that I post the other data to the backend so it all gets sent together conveniently on each click. Here is my updated code for my form:
import React from "react"
export default class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.checkGuess = this.checkGuess.bind(this);
}
handleChange = (event) => {
this.setState({value: event.target.value});
}
handleSubmit = (event) => {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
checkGuess() {
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange=
{this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
and here is the other component that builds the flashcard and posts the data to the endpoint onClick through the checkGuess function. This already works perfectly without the new username value. :
import React, { useState, useEffect, useRef } from 'react'
import NameForm from './NameForm'
export default function Flashcard({ flashcard }) { // recieving
flashcard
prop from our mapping in flashcardlist.js, each w a unique id
const MAX_TRIES = 4
// const [incorrect, setIncorrect] = useState(incorrect)
const [guess, setGuess] = useState(0)
const [flip, setFlip] = useState(false)
const [height, setHeight] = useState('initial') //sets the state for our
initial height to be replaced by the max height
const frontEl = useRef() // lets us have a reference from the front and
back through every rerendering of them
const backEl = useRef()
// const callDouble = () =>{
// checkGuess();
// postData();
// }
async function postData() {
}
const checkGuess = (answer) => {
try {
console.log(this.state.value)
let result = fetch('http://127.0.0.1:5000/post', {
method: 'POST',
mode: 'no-cors',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
key: `${Date.now()}`,
question: flashcard.question,
answer: flashcard.answer,
options: flashcard.options,
guess: answer,
user: this.state.value
})
});
} catch(e) {
console.log(e)
}
if (answer === flashcard.answer) {
setFlip(true)
return
}
if (guess + 1 === MAX_TRIES) {
setFlip(true)
}
setGuess(guess + 1)
// setIncorrect(true)
}
function setMaxHeight() {
const frontHeight = frontEl.current.getBoundingClientRect().height
//gives us dimensions of the rectangle but we only need the height
const backHeight = backEl.current.getBoundingClientRect().height
setHeight(Math.max(frontHeight, backHeight, 100)) // sets the height
(setHeight) to the maximum height of front or back but the minimum is
100px
}
useEffect(setMaxHeight, [flashcard.question, flashcard.answer,
flashcard.options]) //anytime any of these change then the setMaxHeight
will change
useEffect(() => {
window.addEventListener('resize', setMaxHeight) //everytime we resize
our browser, it sets the max height again
return () => window.removeEventListener('resize', setMaxHeight)
//removes the eventlistener when component destroys itself
}, [])
return (
<div
onClick={() => postData()}
className={`card ${flip ? 'flip' : ''}`} // if flip is true classname
will be card and flip, if flip isnt true it will just be card
style={{ height: height }} //setting height to the variable height
// onClick={() => setFlip(!flip)} // click changes it from flip to non
flip
>
<div className="front" ref={frontEl}>
{flashcard.question}
<div className='flashcard-options'>
{flashcard.options.map(option => {
return <div key={option} onClick={() =>
checkGuess(option)} className='flashcard-option'>{option}</div>
})}
</div>
</div>
<div onClick={() => setFlip(!flip)} className='back' ref={backEl}>
{flashcard.answer}
</div>
</div>
)
}
// setting the front to show the question and the answers by looping
through the options to make them each an option with a class name to style
// back shows the answer
and this is the new error:
TypeError: Cannot read properties of undefined (reading 'state')
at checkGuess (Flashcard.js:34:1)
at onClick (Flashcard.js:92:1)
Solution 1:[1]
Since the question has changed a bit based on new code shared by you, please remove the following line:
this.checkGuess = this.checkGuess.bind(this);
Now React components work in a tree structure Root->Children
So you need to figure out whether Flashcard is the root, calling NameForm. Or the other way round.
If Flashcard calls NameForm:
Call
NameForm
as follows while passing in thecheckGuess
function:<NameForm answer={flashcard.answer} checkGuess={checkGuess} />
Then inside NameForm:
handleSubmit = (event) => {
alert('A name was submitted: ' + this.state.value); this.props.checkGuess(this.props.answer, this.state.value); event.preventDefault(); }To support this in Flashcard, change the function signature of
checkGuess
to:const checkGuess = (answer, stateValue) => { ... }
And here you use stateValue instead of this.state.value
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |