Как мне вызвать функцию дочернего компонента в родительском компоненте при использовании setState с функцией обратного вызова?

Справочная информация

Три компонента простого приложения-викторины:

App.jsx  
-- Questions.jsx  
-- Results.jsx 

Чтобы получить доступ к ответам в компоненте результатов И компоненте вопросов, ответы должны быть сохранены в состоянии компонента приложения.

Чтобы изменить состояние компонента приложения, каждый раз, когда пользователь отвечает на вопрос, мне нужно вызывать функцию, которая передается из компонента приложения в компонент вопросов. После установки состояния компонента приложения должен отображаться следующий вопрос. Следовательно, должна быть вызвана функция nextQuestion() в компоненте вопросов. Обычно я бы просто написал setState({results: results}, nextQuestion()), но поскольку nextQuestion() является функцией компонента вопросов, а не компонента приложения, это не работает.

Как я могу решить эту проблему?

Большое спасибо!

В компоненте вопросов:

checkAnswer = (answer) => {

    if (answer !== this.state.solution) {

      let s = this.state;
      this.props.saveResult(s.question, s.solution[0], answer);

      //[...]
    }
  };

newQuestion = () => {
    //[...]

    let question = [...this.state.question];
    let solution = [...this.state.solution];

    const task = taskGenerator.taskDirectory[taskId](); //generate new question + solution
    question = task.question;
    solution = task.solution;
    this.setState({ question, solution });
  };

В компоненте приложения:

saveResult = (question, solution, answer) => {
    let results = cloneDeep(this.state.results)
    results.question = question
    results.solution = solution
    results.answer = answer
    this.setState({ results: results }, newQuestion()); //here is the problem; how do I call the newQuestion function of the child component?
  };
1
John 14 Июн 2021 в 18:10

3 ответа

Лучший ответ

как мне вызвать функцию дочернего компонента в родительском компоненте при использовании setState с функцией обратного вызова?

Короче говоря, вы этого не делаете :) Вместо этого вы передаете состояние от родителя к потомку . На самом деле это корень вашей проблемы:

но поскольку nextQuestion () является функцией компонента вопросов, а не компонента приложения, это не работает.

Короче говоря, разработчик React должен следовать двум «правилам», определяющим, в каком состоянии ваше состояние должно развиваться в вашем приложении. Чтобы понять их, вы должны думать о своем приложении как о «дереве» с App наверху и всеми дочерними компонентами, дочерними компонентами и т. Д. Ниже ...

  1. Состояние должно быть на уровне или выше каждого компонента, которому необходимо использовать состояние.
  2. Состояние должно быть как можно ниже в дереве вашего приложения (при этом все еще следуя №1).

Похоже, вы пытаетесь следовать правилу № 2 и поддерживать низкое состояние (хорошее) ... но ваше приложение нарушает это первое правило: у вас есть состояние (nextQuestion зависит от this.state.question), которое ваше { {X2}} зависит от. Это состояние находится «ниже» (в дереве приложения), чем должно быть, и, поскольку оно не на уровне App, App не может его использовать.

Это означает, что вам нужно переместить nextQuestion (и состояние (я), его питающее) в App, чтобы ваш код в App мог получить доступ nextQuestion. Затем вы можете передать любые данные, которые нужны Question, как props из App.

С этой структурой ваше состояние (и связанные с ним функции, такие как nextQuestion) будут жить настолько высоко, насколько это необходимо (то есть на уровне App), так что вся логика, которая полагается на него, будет иметь доступ, и для любых «нижних» компонентов (например, Question) это состояние будет просто передаваться «вниз по дереву» через props.

0
machineghost 14 Июн 2021 в 15:38
class App extends Component {
...
  setAnswers(answers, callback){
     this.setState({results:answers},callback)
  }
  render(){
    return <Questions setAnswers={this.setAnswers}/>
  }
}

class Questions extends Component {

  onSubmit(answers){
     this.props.setAnswers(answers,this.nextQuestion)
  }
}

Другой способ - отреагировать на изменение состояния дочернего компонента Questions, вероятно, лучший способ.

0
Anuja 14 Июн 2021 в 15:23

Если я правильно понимаю вашу проблему, вы сможете передать функцию в качестве реквизита дочернему компоненту от родителя. Я считаю, что этот пост также отвечает на ваш вопрос. Вызов дочернего метода от родителя

Ура!

0
Jay Jones 14 Июн 2021 в 15:24