Build Multiple Choice Quiz in React Native
AmberJ
Posted on December 2, 2019
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.
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'
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}
/>
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})}
/>
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>
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,
});
}
}
I really enjoyed figuring out this solution! I'm sure there are many other ways. :)
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
November 15, 2024