问题
I'm building a guessing game, where the questions and selection logic is in a component called Questions. I'm having trouble getting App to read the Questions code. I want the state in App to update based on selections in the child component.
I've been trying to reverse engineer a solution from How to pass data from child component to its parent in ReactJS? and https://malithjayaweera.com/2018/01/reactjs-passing-data-react-components/, but I'm not clear on how to apply it to my project.
App:
import React, { Component } from 'react';
import './App.css';
import Timer from "./Timer";
import Questions from "./Questions/Questions.js";
import Results from "../src/Results";
class App extends Component {
state = {
totalTrue: 0,
totalFalse: 0,
}
componentDidMount() {
console.log(`TotalTrue: ${this.state.totalTrue}`);
console.log(`TotalFalse: ${this.state.totalFalse}`);
}
// submit button
handleFormSubmit = event => {
event.preventDefault();
console.log("submit button clicked");
};
callbackHandlerFunction = (selectedOption) => {
this.setState({ selectedOption });
}
render() {
return (
<div className="parallax">
<div className="App">
<div className="wrapper">
<div className="headerDiv">
<h1>Pixar Trivia!</h1>
</div>
<div className="timerDiv">
<Timer />
</div>
<div className="questionSection">
<Questions
handleClickInParent={this.callbackHandlerFunction}
/>
</div>
<div>
<button onClick={this.handleFormSubmit}>Submit</button>
</div>
{/* this.state.articles.length > 0 && ...*/}
<div className="resultsDiv">
<Results
totalTrue={this.state.totalTrue}
totalFalse={this.state.totalFalse}
/>
</div>
</div>
</div>
</div>
);
}
}
export default App;
Questions:
import React, { Component } from "react";
import Select from "react-select";
import "./Questions.css";
const answerChoices = [
{
id: 1,
text: "1. The background image is the carpet from Sid's house in Toy Story. What movie inspired it?",
answers: [
{
label: "2001: A Space Odyssey",
value: false
},
{
label: "The Shining",
value: true
},
{
label: "One Flew Over the Cuckoo's Nest",
value: false
},
{
label: "The Godfather",
value: false
}
]
},
---- full questions cut for space. I'm using https://github.com/JedWatson/react-select and the functionality works. ----
{
id: 8,
text: "8. Who was the original voice of Marlin from “Finding Nemo”?",
answers: [
{
label: "Albert Brooks",
value: false
},
{
label: "Denis Leary",
value: false
},
{
label: "Brad Garrett",
value: false
},
{
label: "William H. Macy",
value: true
}
]
}
];
class Questions extends Component {
state = {
answerChoices,
selectedOption: null,
}
handleChange = (selectedOption) => {
this.setState({ selectedOption });
console.log(`Option selected:`, selectedOption);
const answerValue = selectedOption.value;
if (answerValue === true) {
// console.log(answerValue);
this.setState({totalTrue: this.totalTrue + 1}, () => {
console.log(`New TotalTrue: ${this.totalTrue}`);
});
};
if (answerValue === false) {
// console.log(answerValue);
this.setState({totalFalse: this.totalFalse + 1}, () => {
console.log(`New TotalFalse: ${this.totalFalse}`);
});
};
this.props.handleClickInParent({selectedOption});
}
render() {
// const { selectedOption } = this.state;
return (
<div className="questionsDiv">
<ol>
{this.state.answerChoices.map(question => {
return (
<div className="individualQuestions" key={question.id}>
{question.text}
<Select
value={this.selectedOption}
onChange={this.handleChange}
options={question.answers}
/>
</div>
)
})}
</ol>
</div>
)
}
}
export default Questions;
回答1:
I made some changes and it is working now.
The code looks like this now.
callbackHandlerFunction = ( selectedOption ) => {
const answerValue = selectedOption.value;
if (answerValue === true) {
// console.log(answerValue);
this.setState({totalTrue: this.state.totalTrue + 1}, () => {
console.log(`New TotalTrue: ${this.state.totalTrue}`);
});
};
if (answerValue === false) {
// console.log(answerValue);
this.setState({totalFalse: this.state.totalFalse + 1}, () => {
console.log(`New TotalFalse: ${this.state.totalFalse}`);
});
};
}
and
handleChange = (selectedOption) => {
this.props.handleClickInParent(selectedOption);
}
回答2:
Look at this line in Question:
this.props.handleClickInParent({selectedOption});
It is passing { selectedOption } to callbackHandlerFunction in App. Now, that last function in App takes a single argument selectedOption, and proceeds to update the state using it. All together, you are updating the state in App using:
this.setState({ { selectedOption } }); // this is wrong.
To fix the issue, use this.props.handleClickInParent(selectedOption) (no curly braces) in Question instead.
Alternatively, if you ignore the above, you can also fix the issue by changing the signature of callbackHandlerFunction so that it look like this:
callbackHandlerFunction = ({ selectedOption }) => { // note the curly braces.
this.setState({ selectedOption });
}
来源:https://stackoverflow.com/questions/53898408/react-communication-problem-from-child-to-parent