Creating a Trivia App with Ignite — Part I

UPDATE 1/09/2024: This has now been updated to be compatible with Ignite Exp[ress]o (9.3.1).
If you’ve never used MobX State Tree or TypeScript, the Ignite stack can be a bit unfamiliar! If you’re curious why we love this stack, take a look at this doc.
In this post, we’ll go through the steps of creating the data model for a trivia app to illustrate how to use our stack with real examples.
(Psst, spoiler alert! If you’d like to follow along with real live code, check out the finished app!)
First things first, let’s Ignite our new app! Check out the ignite-cli documentation to read up on everything Ignite can do!
npx ignite-cli new IgniteTrivia --install-deps --remove-demo
As the Ignite commands run you can just accept the the defaults for the remaining prompts:
✅ What bundle identifier? · com.ignitetrivia
✅ Where do you want to start your project? · /Users/jpoliachik/code/IgniteTrivia
✅ Choose a workflow: · Expo Go
✅ Do you want to initialize a git repository? (Y/n) · Yes
✅ Which package manager do you want to use? · yarn
After Ignite finishes running, cd
into the folder and run yarn ios
or yarn android
and you should see something like this:

Defining Our Models
Next, let’s start building our data models. We’re going to use The Open Trivia Database as our data source, so we’ll build our models to match that data.
Question
We need a question model! Each question has the following properties:
id
, category
, type
, difficulty
, question
, correctAnswer
, incorrectAnswers
Let’s create the MobX State Tree (MST) model:
npx ignite-cli generate model question
This will create two files in our models folder, app/models
, which contains a few files:
Question.ts
Question.test.ts
We won’t be writing unit tests quite yet, so we’ll focus on Question.ts

This file has a couple different parts. First there’s QuestionModel
, which is the heart of this file. It’s the MST model definition. Each model instance has properties, like a regular JS object, but it also has views (computed values), and actions.
At the bottom of the file, we define some TypeScript interfaces which will help TypeScript to know about the shape of our data as we use it throughout the app.
We’ll focus on properties first, so let’s add the properties we want each Question
to have:
Let’s unpack this a bit.
We have id
, which is types.identifier
. This is MST’s version of a primary key. It has to be unique, and it allows you to do some helpful things like reference your model instance by only its identifier. You can read a bit more about identifiers here.
Then, we have some string properties: category
, question
, and correctAnswer
. These are all free-form text values, and we’ve made them optional by using types.maybe()
. That means these values can be undefined.
We also have the property incorrectAnswers
which is an array of strings. Instead of types.maybe()
, we’ve used types.optional()
. This allows us to not specify a value for this property, but instead of being undefined, it will take a default value of []
.
Finally, we have type
and difficulty
which is are both enumerations. This forces the value to be one of a predetermined list of values, in the case strings.
Question Store
Since we’ll be listing more than one trivia question, we need a place to store a list of them. So let’s create QuestionStore
.
npx ignite-cli generate model question-store
IGNITE TIP 🎉: If you Ignite apps as often as we do, you can abbreviate
generate
asg
, likenpx ignite-cli g model <model-name>
This file looks a lot like question.ts
did when we first generated it, but we’re going to add different properties. For now, it only has one: an array of type QuestionModel
. This will be an array of MST instances. We may decide we need more properties later, but this will be enough to get started.
Hooking up the API
Okay, we have some models describing the shape of data that we want. Now let’s get some data.
API Service
Ignite comes with an API service all ready to customize, so let’s customize it.
Changes to config.dev.ts
, api.ts
and api.types.ts
:
Here’s what we did:
- We updated the base URL in
app/config/config.dev.ts
- Updated the function return types to use
QuestionSnapshotOut
. Snapshots are the serialized version of MST models, without all the dynamic features like views, and actions. You can think of snapshots as the immutable, plain JS object version of your MST model. This type definition lives inapi.types.ts
. - Added a uuid to each record with
react-native-uuid
. You can add it to your project by runningyarn add react-native-uuid
.
Fetching the Data
Now that our API service is setup, let’s tell our models how to call the API and populate data into our store.
It’s time to make our first MST action
.
But first, let’s take a look at something that comes standard in our generated Question Store Model.
You’ll notice that there’s already an action .actions(withSetPropAction)
. This is a helper will allow you to set property values directly while retaining type safety and also is executed in an action. This is useful because often you find yourself making a lot of repetitive setter actions that only update one prop.
We’ve added a new action! getQuestions
calls the API method to get the array of snapshots from the API, and then we set the questions
prop with the setProp
helper function. Because of this helper, we’re able to await for the api.getQuestions
call to resolve and set our prop to those results, instead of the mobx-state-tree flow generator function syntax.
That’s it for Part I! We now have a solid data model, and a way to populate our store from an external API. Next time, in Part II, we’ll consume our data by hooking up a UI!

Robin Heinze is a senior software engineer building React Native apps at Infinite Red, a mobile/web app design and development agency. Follow her on Twitter or Github.