【问题标题】:React communication problem from child to parent反应孩子与父母的沟通问题
【发布时间】:2019-05-22 17:31:29
【问题描述】:

我正在构建一个猜谜游戏,其中问题和选择逻辑位于一个名为 Questions 的组件中。我无法让应用程序读取问题代码。我希望 App 中的状态根据子组件中的选择进行更新。

我一直在尝试对 How to pass data from child component to its parent in ReactJS?https://malithjayaweera.com/2018/01/reactjs-passing-data-react-components/ 的解决方案进行逆向工程,但我不清楚如何将其应用到我的项目中。

应用程序:

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;

问题:

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;

【问题讨论】:

  • 您在 Question 组件的状态中缺少 totalTrue 和 totalTrue,您在 handleChange 中设置它们。在来自父级的回调函数中,您正在传递 selectedOoption 但您正在设置的父级状态中没有 selectedOption 属性。
  • 我希望在执行 handleChange 时让 Questions 更新 App 中的状态。这根本不可能吗?

标签: javascript reactjs ecmascript-6 components


【解决方案1】:

我做了一些更改,现在可以使用了。

代码现在看起来像这样。

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}`);
      });
  };
}  

handleChange = (selectedOption) => {

    this.props.handleClickInParent(selectedOption);
  }

【讨论】:

  • 这行得通,谢谢!看来我的组件之间的连接颠倒了。
  • 我之前在评论中提到过。
  • 我想我误解了。不过还是谢谢你。
【解决方案2】:

Question中的这一行:

this.props.handleClickInParent({selectedOption});

它在App 中将{ selectedOption } 传递给callbackHandlerFunction。现在,App 中的最后一个函数接受一个参数selectedOption,并继续使用它来更新状态。总之,您正在更新App 中的状态:

this.setState({ { selectedOption } }); // this is wrong.

要解决此问题,请改用Question 中的this.props.handleClickInParent(selectedOption)(无花括号)。

或者,如果您忽略上述内容,您也可以通过更改callbackHandlerFunction 的签名来解决此问题,使其看起来像这样:

callbackHandlerFunction = ({ selectedOption }) => { // note the curly braces.
    this.setState({ selectedOption });
}    

【讨论】:

  • 我已经尝试了 Sameer 和您的建议,但仍然无法正常工作。这是带有最新更改的 repo 分支:github.com/irene-rojas/pixar-react/tree/refactorresults
  • @IreneRojas 我看到了 github 仓库。您应该将花括号添加到 callbackHandlerFunction 签名或从 this.props.handleClickInParent({selectedOption}) 中删除花括号,而不是两者。
  • 使用代码库中的代码,尝试在Question 中使用this.props.handleClickInParent({selectedOption}) 而不是this.props.handleClickInParent(selectedOption)
  • 我进行了更改,但我得到“新的 totalFalse:未定义”(等),结果 div 始终显示为零。我将更改推送到 refactorresults 存储库。我仍然是 React 的新手,并试图围绕父子之间的组件通信。
  • @IreneRojas 好的,但是App 中的状态正在正确更新,这样就解决了最初的问题。至于你现在提到的问题,你必须在Question的状态下将totalTruetotalFalse的初始值设置为0。此外,您必须通过状态访问它们的值;例如,this.state.totalTruethis.state.totalFalse(相对于 this.totalTruethis.totalFalse)。如果您需要更多帮助,您可以更新您的问题(或提出新问题)。这样,我可以相应地更新我的答案。
猜你喜欢
  • 1970-01-01
  • 2011-02-21
  • 2021-04-25
  • 2020-01-29
  • 2019-02-04
  • 2011-02-20
  • 1970-01-01
  • 2014-02-16
  • 2017-07-01
相关资源
最近更新 更多