PLEASE keep in mind that this is a living document being written as I figure this project out. I might not necessarily be following best practices, and could potentially make some mistakes. I (personally) find following along with a practical project a more useful learning tool than lessons or tutorials, which can often get abstract or put the cart before the horse, but it does come with tradeoffs. I’ll try and note where I’m just taking my best guess, and even come back to edit any egregious mistakes if they arise, but be aware this isn’t an expert tutorial (and if you happen to catch any major oopsy-goofs on my part, please contact me!)
Okay with that out of the way, let’s get started!
I love trivia, so I’m making a trivia app using the Open Trivia Database API. My goal is to make a 30-question game of 10 easy, medium, and hard questions apiece where users race against the clock to get as many questions correct in as little time as possible. I might add some bells and whistles down the line, but for now I’m just focusing on that core functionality.
My initial goal is to explore how to implement global state using hooks instead of Redux. Two articles that were of immense help getting up and running were this one by Ebenezer Don of LogRocket and this Medium article by Martin Crabtree. Both implement state slightly differently and I ended up leaning more towards the second for my own project, but both are hugely useful.
Here’s the top level overview of what I need to do for phase one:
- Create a basic reducer with its initial state
- Create a store that contains global state and make it globally accessible
- Make an API call that interacts with global state to ensure everything works at a basic level before building on top of it
Now that we have an outline of our basic steps, let’s get into the actual implementation.
Step 1: Basic reducer + initial state
create-react-app, I create a new file called
store.js in the
src folder. This will be in charge of the global state. For values I'll need to keep in state, I know that I need one to keep track of whether the API is fetching, and an array to keep track of the questions. More values will definitely be necessary down the line, but remember this is just a basic start. As with Redux, the reducer is a pure function. To test my initial setup, I'm aiming to make an API call that retrieves 30 questions and saves them in state, so for now I'm just going to make an action for when the call is dispatched, and an action apiece for when the call returns successfully and unsuccessfully. I'm including console logs for in-browser testing purposes of seeing exactly what I'm getting back.
Step 2: Make state globally accessible
Next I use React’s Context API to create a context object with its initial state set to, appropriately enough,
initialState. Then I create a store provider component by creating a function that uses the
useReducer hook and returns the context object's
Provider component with the reducer hook set as its
In order to make state globally accessible, I just need to wrap my app component in the
… and include the following
useContext call within any component that needs to access global state:
Step 3: Test global state with API call
Eventually I’ll need to split the app up into a component hierarchy, but for purposes of testing that everything is wired up correctly I’m just keeping everything in
App.js for now. I'm also trying to keep my imported packages to a minimum, but I do like axios for making HTTP requests.
I create a component
clickMe that when clicked, fires the function
fetchAndDispatchTrivia. This function dispatches "FETCH_TRIVIA_START" to tell global state that the app is in the process of fetching. It then initializes an empty array to store the trivia questions, and chains together three separate calls to the API (for 10 easy, medium, and hard questions), pushing the results of each call to the questions array. If all goes well, the function should dispatch a success action and a 30-member array of trivia questions should be saved to global state. Otherwise it should throw an error. While the app is fetching, the "Click for trivia" text should be replaced with a "please wait" component (based on reading the
isFetching value from global state).
Testing in-browser, everything works as expected, so I’m free to move on to more core implementation of the app interface, which I’ll cover in my next blog installment.