1

This is my first React app and I have read the official tutorial/doc and am following the guidelines there. I thought I had a decent understanding of the concepts but obviously I am missing something as I am unable to pass value and id back to parent component so I can do the grading in parent component.

Basically this is a simple quiz (or q & a) app where the array[0] is question and array[1] is answer: allProblems = [[q1,a1],[q2,a2], ...].

class ChildComponent extends React.Component {

    inputAnswer(id, e) {
        e.preventDefault();
        this.props.onAnswer(e.target.value, id);
    }

    render() {
        const { problem, id, answer } = this.props;                                                                     

      return (
        <li>
            {problem[0]} = <input value={answer} onChange={(e) => this.inputAnswer(id, e)} />
        </li>
      );
    }
  }

  class ParentComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            answer: null,
        };
    }

    handleAnswer(answer, id) {
        alert(id);

        this.setState({
            answer: answer,
        })
    }

    render() {
        const rows = [];

        this.props.allProblems.forEach((problem, index) => {
            rows.push(          
              <ChildComponent 
                key={index}
                problem={problem} 
                id={index}
                answer={this.state.answer}
                correct={this.state.correct}
                onAnswer={() => this.handleAnswer()}
              />
            );
        });

      return (
        <div>
            <h1>Problems</h1>               
            <ul>{rows}</ul>
        </div>
      );

    }
  }

Thanks!

woa
  • 23
  • 3
  • I think this problem might answer your question https://stackoverflow.com/questions/38394015/how-to-pass-data-from-child-component-to-its-parent-in-reactjs/38397755#38397755 – Shubham Khatri Jan 22 '18 at 06:51
  • @ShubhamKhatri thanks. I actually found that before I posted my question, and my issue is very similar but unfortunately I was not able to use it to resolve the issue. – woa Jan 22 '18 at 07:00
  • what is `{problem[0]} = this.inputAnswer(id, e)} />` doing – Shubham Khatri Jan 22 '18 at 07:02
  • I believe he's trying to output the text value of problem[0], then "=" as text, and then the JSX – kng Jan 22 '18 at 07:13
  • problem is an array where problem[0] is the question and problem[1] is the answer. The idea is then to use the value from the input as the answer and compare it to problem[1] in parent component when grading. allProblems is an array containing a variable number of questions, which in turn are also arrays which hold the question and answer (problem[0] and problem[1] respectively) – woa Jan 22 '18 at 07:14
  • I think my answer below solves your issue, take a look – kng Jan 22 '18 at 07:14
  • Possible duplicate of [How to pass data from child component to its parent in ReactJS?](https://stackoverflow.com/questions/38394015/how-to-pass-data-from-child-component-to-its-parent-in-reactjs) – Hemerson Carlin Jan 22 '18 at 07:21

2 Answers2

1

You have this:

  onAnswer={() => this.handleAnswer()}

inside the forEach callback in your parent component.

What you need is this:

   onAnswer={(answer, id) => this.handleAnswer(answer, id)}

Otherwise, handleAnswer isn't going to receive anything.
So in total, inside your callback you should be pushing this:

  <ChildComponent 
        key={index}
        problem={problem} 
        id={index}
        answer={this.state.answer}
        correct={this.state.correct}
        onAnswer={(answer, id) => this.handleAnswer(answer, id)}
      />

Some more information (optional):

You could also condense your code, and improve performance by making your handler an arrow function, which means you don't have to worry about the value of 'this' when its being used. So inside your child component, you could change your handler to:

   handleAnswer = (answer, id) => {
       alert(id);

       this.setState({
           answer: answer,
       })
   }

And then you could do this:

   onAnswer={this.handleAnswer}
kng
  • 607
  • 3
  • 9
  • Thanks so much. I think that solved it and will accept is as the answer. – woa Jan 22 '18 at 07:21
  • Followed your updated suggestions and works. Thanks for not only caching/fixing my error but also for guidance on how to improve my code. – woa Jan 22 '18 at 07:46
  • meant to say catching/fixing - but too late to edit it :) – woa Jan 22 '18 at 07:55
0

I think that you should have have onBlur instead of onChange event. Also, if id is coming from props, no need to pass it in the event handler param, you can directly extract it in onBlur handler:

{problem[0]} = <input value={answer} onBlur={(e) => this.inputAnswer} />


inputAnswer(e) {
        e.preventDefault();
        this.props.onAnswer(e.target.value, this.props.id);
    }
Umesh
  • 2,704
  • 19
  • 21
  • Thanks! I will try your suggestions. The reason I was passing id in the event handler was that I wanted to be sure that it was the correct id for that particular problem. – woa Jan 22 '18 at 07:25