反应孩子与父母的沟通问题

Posted

技术标签:

【中文标题】反应孩子与父母的沟通问题【英文标题】: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 ***s",
            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 中的状态。这根本不可能吗? 【参考方案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)。如果您需要更多帮助,您可以更新您的问题(或提出新问题)。这样,我可以相应地更新我的答案。

以上是关于反应孩子与父母的沟通问题的主要内容,如果未能解决你的问题,请参考以下文章

闭关数日研发智能玩具小绿亲子

反应我必须重新渲染父母才能重新渲染孩子吗?

反应:孩子点击改变父母的状态以重新渲染

反应父母对孩子道具传递而不重新渲染

反应孩子正在通过道具改变父母状态......我不清楚原因

挂钩父母在孩子之前卸下