Build Multiple Choice Quiz in React Native

amberjones

AmberJ

Posted on December 2, 2019

Build Multiple Choice Quiz in React Native

This article is relevant to React Native!! If you are using React, you might find some state logic useful, but the components can not be transferred.

React Native Elements has a component called CheckBox which is a great base for a list, but it needs a little hacking to get it to interact like a multiple choice quiz.

CheckBoxes allow users to complete tasks that involve making choices such as selecting options, or switching settings on or off. It provides a clear visual of either a true or false choice.

Since I couldn't find a native quiz component so I thought this would do the trick. I wanted a user to be able to click on a checkbox, or 'answer' and have a visual indicator change. The user would only be able to select one checkbox at a time though.

I couldn't find an example of using CheckBox this way online that actually worked - I'm sure its probably out there - so here is how I customized it to become a simple dynamically rendering quiz component.

Imgur

Getting Started

To use the CheckBox, download the react-native-elements dependency
with your preferred package manager.

Then import it into the top of your component like so.

import { CheckBox } from 'react-native-elements'
Enter fullscreen mode Exit fullscreen mode

The most simple implementation of CheckBox is below, but there are many props available to add to it.

<CheckBox
  title='Click Here'
  checked={this.state.checked}
/>
Enter fullscreen mode Exit fullscreen mode

Adding an onPress prop to CheckBox allows a function to toggle the state of 'checked' between true and false.

<CheckBox
  title='Click Here'
  checked={this.state.checked}
  onPress={() => this.setState({checked: !this.state.checked})}
/>
Enter fullscreen mode Exit fullscreen mode

The Problem

That's cool, but what happens when I want to have multiple checkboxes to display the answer choices?

As is, the checked state of all of them will be effected and toggled to all true or all false.

I went ahead and added some more props with explanations.

<View>
  <Text style={styles.question}>{question}</Text>
    <View>
      {answers.map((answer) => (
        <CheckBox
          center
          key={answer.id}
          title={answer.choice}
          // if these are not empty strings, the default checkbox appears
          checkedIcon=""
          uncheckedIcon=""
          checked={this.state[answer.id] || false}
          // ternary conditionally renders the color of choice container 
          containerStyle={this.state[answer.id]
          ? { backgroundColor: answer.isCorrect
              ? 'lightgreen' : 'pink' } : null}
          onPress={() => this.handleSelection(answer)}
         />
        ))}
    </View>
</View>
Enter fullscreen mode Exit fullscreen mode

Selection State Solution

I asked 2 questions in handleSelection:

  • has any answer been selected before?
  • if so, is it the same answer or a new answer?

A good 'ole shuffle toy problem came to mind. I needed a variable to keep track of the previous selection to compare it to the current selection. Then, I'd set variable to the current value for the next comparison.

The magic happened in dynamically setting and referencing the state, seen as this.setState({[answer.id]: true}).

 handleSelection(answer) {
    const { isSelected, prevChoice } = this.state;

    // has any answer been selected before?
    if (isSelected === false) {
      // if not, we set all state to current answer variables
      this.setState({
        isSelected: true,
        [answer.id]: true,
        prevChoice: answer.id,
      });
    } else {
      // A choice is already selected
      // If it is the same choice,
      prevChoice === answer.id
        ? this.setState({
          //  toggle off
          isSelected: false
          //  assign state of answer to false
          [answer.id]: false,
          //  reset the prev choice
          prevChoice: null,
        })
        // else we know it is a new choice,
        // we dont change state of 'isSelected'
        // set the previous to current
        : this.setState({
          // assign state at previous value false
          [prevChoice]: false,
          [answer.id]: true,
          // assign new id as prev
          prevChoice: answer.id,
        });
    }
  }
Enter fullscreen mode Exit fullscreen mode

I really enjoyed figuring out this solution! I'm sure there are many other ways. :)

💖 💪 🙅 🚩
amberjones
AmberJ

Posted on December 2, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related