Random Quote – Part 9 – React Hooks and JSON: Using various front end stacks

4 min read

Building a random quote machine with React Hooks and JSON

This is Part 9 of the Making a random quote machine in a few different flavors series.

You can read more about this project’s background on the project’s page. Or start from the beginning with part 1 of this series.

In flavor #8, I’m creating function components in a React app with Hooks and I have the data (quotes) inside an array. In this flavor, the data is inside a JSON file (like in flavor #7), but here I’m creating function components in a React app with Hooks (not using React classes like previously).


In Part 10 (to be posted next week), I will cover a tenth flavor and will be using Redux.

If you’re curious about the next flavors and would like to make a writer very happy today, you should join Morse Wall’s newsletter.


Flavor #9: HTML + CSS + React Hooks + JSON with quotes

Like previously in flavor #7, I’m storing the quotes in a separate JSON file in jsDelivr, a public CDN.

Actually, since much of the code in this flavor remains the same as in flavor #7, it may be helpful to give that writing a quick read.

Kickstarting this flavor, I’m initializing the quote state variable to "":

"use strict";

//defining an array for the quotes
let quotes;
//defining the function component.
const App = () => {
  //initializing the initial state
  const [quote, setQuote] = React.useState("");
}

This initial state is used during the initial render and the app will then re-render when it has finalized fetching the data from the JSON file.

For more on useState and React Hooks check flavor #8.

Controlling asynchronous code in React with Hooks

In order to fetch the data from the JSON file, I’m using the useEffect Hook.

useEffect allows me to run imperative code (in which I tell the code, step-by-step, how to execute) using a declarative programming language (in which I describe what I want the application to accomplish and someone else - in this case React - implements it).

//defining the function component.
const App = () => {
  //initializing the initial state
  const [quote, setQuote] = React.useState("");

  //asynchronous function that fetches JSON content, populates the quotes array and updates state with a quote (following the fetch being complete)
  React.useEffect(async () => {
    const responseJSON = await fetch(
      "https://cdn.jsdelivr.net/gh/morsewall/jsondb@master/db.json"
    );
    const responseObject = await responseJSON.json();
    quotes = responseObject.quotes;
    let initialQuote = quotes[Math.floor(Math.random() * quotes.length)];
    setQuote(initialQuote);
  }, []);
}  

The async/await function inside useEffect follows a more step-by-step imperative approach and this allows me to force things to happen, in order, while dealing with asynchronous code. fetch() would, otherwise, execute without pausing the execution of the rest of the code, leading me to eventually get a reference to quotes being undefined on the browser console since setQuote would run and try to access a random quote from the quotes array before the array has been populated.

The async/await function passed to useEffect will run after the render is committed to the screen. This is great since I don’t want to stop the component from mounting. I want the component to go ahead, set the initial state in the local state of the component, render and only re-render when fetch() has finished fetching the requested resource from the network (data from the JSON file).

By using useEffect, I’m effectively telling React that the component needs to do this “effect” after the browser has painted. React will call the function passed to useEffect later, after performing the DOM updates.

Disclaimer: React Suspense

Hooks are still very new and “best practices” are still being figured out for some of the less common patterns. For instance, a new way to fetch data is in the works with React Suspense and in the longer term, the React core team will recommend using Suspense for data fetching.

By default, effects run after every completed render and since I’m setting the state after every data fetch, the component would update and the effect would run again. It would fetch the data again and again. To avoid this, and only fetch data when the component mounts, I provide an empty array ([]) as second argument to useEffect to avoid activating it on component updates. This tells React that the effect doesn’t depend on any values from props or state, so it never needs to re-run.

And done. The rest of the code remains the same as in flavor #7.

You can check the project live. Source code for flavor #9 in Github.

Live project Source code


In Part 10 (to be posted next week), I will cover a tenth flavor and will be using Redux.

If you’re curious about the next flavors, you should join Morse Wall’s newsletter. I think you’ll like it a lot!


So, what did you like about this post? Leave a comment or come say hello on Twitter!

Also, if you have built a random quote machine after reading this post, share it below as a comment. Really excited to see what you create!

Happy coding!

Enjoyed this content?

Help keep it coming by sending a donation or buying me coffees.
You can also join Morse Wall's newsletter, or subscribe to various site feeds to get notified of new posts or follow Morse Wall on social media.

Leave a comment

by Pat
by Pat