Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a survey using React but stuck finding a way to have questions dependent on certain responses

I am creating a relatively basic website that provides a survey to users. But I've run into a dead end at the moment trying to figure a way to have the next question dependent on the answer to the previous question. So far I have a separate page holding an array of roughly 40 questions, a component that maps each question with its text and answer, and the page where they are rendered.

const questionArray = [
  {
    question: "how old are you?",
    answers: [
      "younger than 15",
      "between 15 and 20",
      "older than 20",
    ],
    questionId: 1,
  },
  {
    question: "are you a student?",
    answers: ["yes", "no"],
    questionId: 2,
  },
  {
    question: "where do you live",
    answers: ["QLD", "NSW", "VIC", "ACT", "NT", "TAS", "WA"],
    questionId: 3,
  },
];

const QuestionComponent = ({ question, options, selected }) => {
  const [answer, setAnswer] = useState(options);
  return (
    <div>
      {question}
      {answer.map((text, index) => (
        <button
          key={index}
          onClick={() => {
            setAnswer([text]);
            selected(text);
          }}
        >
          {text}
        </button>
      ))}
    </div>
  );
};

class QuestionPage extends Component {
  state = {
    questions: [],
  };

  getQs = () => {
    this.setState({ questions: questionArray });
  };

  componentDidMount() {
    this.getqs();
  }

  render() {
    return (
      <div>
        {this.state.questions.map(
          ({ question, answers, questionId }) => (
            <QuestionComponent
              question={question}
              options={answers}
              key={questionId}
            />
          ),
        )}
      </div>
    );
  }
}

this method so far basically just lists all the questions through the component. I just can't work out how to go about changing it so as instead of listing all the questions initially, a question is added depending on the previous answer. For example, if the user answered question 1 with younger than 15 the next question would be question 3.

Any help would be greatly appreciated!

like image 834
SkinnyBetas Avatar asked Oct 18 '25 09:10

SkinnyBetas


2 Answers

There were some syntax errors in your original code to begin with.

I refactored things a bit:

  • Questions aren't part of state; the questions themselves shouldn't change.
  • Answers are now stored in the QuestionPage's state.
  • Questions have an optional condition field, which is a function that returns whether or not this question should be shown.

NB: The below is dry-coded so there might be some silly typos or such in there.

const questionArray = [
  {
    question: "how old are you?",
    answers: [
      "younger than 15",
      "between 15 and 20",
      "older than 20",
    ],
    questionId: 1,
  },
  {
    question: "are you a student?",
    answers: ["yes", "no"],
    questionId: 2,
    condition: ({ answers }) => answers[1] != "older than 20",
  },
  {
    question: "where do you live",
    answers: ["QLD", "NSW", "VIC", "ACT", "NT", "TAS", "WA"],
    questionId: 3,
  },
];

const QuestionComponent = ({ question, answer, onSelect }) => {
  const { question, answers } = question;
  return (
    <div>
      {question}
      {answers.map((text, index) => (
        <button
          key={index}
          onClick={() => {
            onSelect(text);
          }}
        >
          {text}
        </button>
      ))}
    </div>
  );
};

class QuestionPage extends Component {
  state = {
    answers: {},
  };

  render() {
    const questions = questionArray.filter(q => {
      if (!q.condition) {
        // no condition set; always visible
        return true;
      }
      return q.condition({ answers });
    });
    return (
      <div>
        {questions.map(question => (
          <QuestionComponent
            question={question}
            answer={this.state.answers[question.questionId]}
            key={question.questionId}
            onSelect={answer => {
              const answers = {
                ...this.state.answers,
                [question.questionId]: answer,
              };
              this.setState({ answers });
            }}
          />
        ))}
      </div>
    );
  }
}
like image 138
AKX Avatar answered Oct 19 '25 22:10

AKX


You actually want to build a decision tree to resolve that issue, for an example, you can have all the questions in the array and having a requireResponses[] field

e.g:

const questionArray = [
     {
          question: "how old are you?",
          answers: ['younger than 15', 'between 15 and 20', 'older than 20'],
          questionId: 1
     },
     {
          question: "are you a student?",
          answers: ['yes', 'no'],
          questionId: 2,
          requireResponses: [{ questionId: 1, answer: 0 }],
     },
     {
          question: "where do you live",
          answers: ['QLD', 'NSW', 'VIC', 'ACT', 'NT', TAS', WA'],
          questionId: 3,
          requireResponses: [{ questionId: 1, answer: 1 }, { questionId: 2, answer: 1 }],
     }
];

and compare the questionId with the requireResponses.

You can also have a look to that library who can help you a lot to develop your app.

like image 21
oktapodia Avatar answered Oct 19 '25 23:10

oktapodia



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!