Learn React.js by example: Building an Axolotl facts app, a 2021 guide

Support us on Patreon

Today we will create a basic application that shows information about Axolotls, the Axolotl is a critically endangered neonetic salamander, due to this fact, they have been gaining attention on the internet.

We won't write the information displayed ourselves, instead, our app will request a URL that will serve as the data to display, our application is nothing more than a "dumb" display for that data.

The URL our website will contact is provided by the AxolotlAPI, which also has more resources you can check out on that Github organization link, in this tutorial we will use their service for educational purposes, running our website on our machines only.

Update: The AxolotlAPI block requests due to a CORS policy, the guide will make a quick "fake" API to return some data.

What is, and why React?

To understand what is and why we will use React here, you must know that React is not needed, you can build beautiful applications with or without it, React is a tool for a job, and our job is to build a web application.

React is even less needed for an application like this, it is basic, but it doesn't mean we can't use React on it.

If you have no idea about web development, take a look at Getting Started with HTML, on the MDN, but if you want to skip and go directly to React, there is no problem!

HTML(HyperText Markup Language) is used when developing with Reactjs, it gives us elements that we can use to build a structure with, CSS(Cascading Style Sheets) is used to style these elements.

HTML is the definition of the elements that are on your page, like a link, a button, a paragraph, and so on!

CSS is the style of these elements, how big is this button? What color will be the text?

When you open a website, like this exact one you're reading, your browser will read through the HTML elements provided by the page, and the CSS, creating the elements accordingly, this is the process of parsing.

The result you see on the screen is nothing more than the representation of the HTML and CSS, it was written and parsed by your browser, this is also why different browsers can display certain elements in different ways.

HTML and CSS are the dad and mom of web development, but they are not enough in certain scenarios. What if I want to change something on the page when the user presses a button? How the browser will do something after the page loaded?

Enter Javascript! Javascript can make cat pictures dance around on the screen and dynamically show data for the user, without requiring another page to be loaded. JS has many uses, it makes our websites dynamic, it changes to content in the way we want, and how we want.

React is made using Javascript, and there is nothing special about it, React lets you group a bunch of HTML components and CSS, with some Javascript functionality, and call it a React Component, this component can now be used in different parts of your website, a button, a piece of text, and so on!

A basic overview of React usage:

  • My website has a button on every page, this button is red, and when the user clicks on it, the website will display a warning saying Hello
  • If I want to change my button, I have to edit all pages where my button is
  • With React I can make a RedButton component, when I add RedButton to a page, it will be red, and show the warning as it should, but now I only have to care about one file

React provides more than the above example, which is made just to give you a better picture of what we are talking about.

Creating your first React project

Straight to what you need:

  • Download and install Nodejs
  • Download and install Visual Studio Code(optional), if you install it, follow its little guide, you will only have to open the React project folder on File, and Open Folder to start editing the project using it

Starting the project:

  • Create a new folder anywhere you want
  • Open the command prompt, by pressing the Windows key + R, typing cmd on the Run window that will open, and Enter
  • Open the folder you created, and copy the path to it
  • Type on cmd: cd path/of/your/folder and Enter
  • Type and enter on cmd: npx create-react-app axolotl-app
  • After the project is created and you can type on cmd again, type cd axolotl-app, and then npm start
  • Your project is now running at the URL http://localhost:3000/

Good! Below are some notes:

  • To stop the project, type CTRL + C on the cmd window
  • To run the project again, just "cd" back to that folder on cmd, and type npm start
  • If you downloaded Visual Studio Code, open the folder that contains the project files, so you can edit the code there

From the Create-React-App readme, this is the folder structure generated for the project:

axolotl-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    └── serviceWorker.js
    └── setupTests.js

A lot of files? Do not worry about them! Create react app generated usual files we would use in a React project, some things there we may not even touch.

Let's create the Axolotl React app

Currently, our website only shows the spinning React logo and nothing more, this is the code doing that:

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

You can access this file at src/App.js

If this file is responsible for rendering that page on the screen, let's understand better what it is doing.

This is a Javascript(ending with .js) file, so it runs... Javascript, you may think that because we are using React, there is something special on this file, but far from that, this is Javascript, although create-react-app got certain things working for us under the hood.

import logo from './logo.svg';

This line uses import to import a file called logo.svg, this is the React logo image! The variable logo now holds the value we can pass as a source for an img element.

import './App.css';

Import is now being used to import a CSS file, this import allows the styles from the specified file to be used.

Right after these two imports, we have a function declaration.

function App() {

This function returns a bunch of HTML, which is what you see on the screen!

How this Javascript file is returning HTML?

If you know Javascript, you will notice that what is being done here is quite... impossible.

The HTML inside this file isn't truly HTML, it is JSX, to not be confused, one of the things create-react-app is doing for you is setting up JSX. You can learn more about JSX.

How the image works?

<img src={logo} className="App-logo" alt="logo" />

As this is JSX, some JSX specific features can be used, using brackets you can type Javascript code inside it, in this case src={logo} is using the logo variable as the value for this property.

export default App;

This is exporting the function App, everything you export can be imported, by exporting the App function it can be used somewhere else, and it is being used on our app entry point, the src/index.js file.

The App function is a React Component!

Changing the app code

We want to create a simple website that shows Axolotl facts, let's think about what we may want on this website:

  • Beautiful Axolotl pictures from the online service
  • A text showing the Axolotl fact
  • A button for another fact
  • A footer with external links for more resources

This is great! We know what we want on the website, having some idea of what our page will have, but... We need to think about it using React Components.

We need to define the components our page will have, and the hierarchy they will build.

  • The App component will piece other components together, having some elements itself
  • A Fact component will hold the elements needed to display the fact
  • The Footer component will have everything related to the footer
  • A Button component will wrap the button that generates a fact, in case we ever need another button
  • An image component
App
├─── Footer
├─── Fact
├── Button
├── Image

Looking simple, right?

How to create React components

As we are using Create React App, just follow the boilerplate pattern, in this case, create a file with the component name .js inside the src folder, the file must export a function that is our component.

If you want you can duplicate the App file, rename it, and change its contents.

Code for the Button component

Create the Button.js file inside the src folder.

Paste the following inside it:

function Button() {
    return 'Hello World';
}

export default Button;

Go back to the App.js file

To start creating our first component interactively, we will import it and use it inside our App.js file.

Import it by adding one import for the Button component:

import logo from './logo.svg';
import './App.css';
import Button from './Button';
// ... other code

Now we can use our component in the code! Add it anywhere inside the App return, I put it inside the first div:

 return (
    <div className="App">
      <Button/>
      <header className="App-header">

If you open the webpage at http://localhost:3000/ you will see that the Button component will appear.

The text Hello World will appear at the top of the page.

Going back to Button.js, we can now create the button component.

Change it like so:

function Button({children}) {
    return <button>{children}</button>;
}

And replace its usage on the App.js component to:

<Button>
        I'm the children of the button component
</Button>

On the App page, you will now see a button that says "I'm the children of the button component".

But how?

The big addition to the button component is the children's prop, the children's prop has all the children that the component has when you're using it.

Button({children})

The declaration of our function now has {children}, this is a destructuring assignment, you don't have to remember every detail of what is being done, just understand it and follow patterns until you learn more about it.

The children are a property being passed to our Button component with the children elements, our Button component is a regular function, it receives the component props, which is being destructured for us to quickly access the property.

Button({children})

Does the same as

function Button(props) {
    const children = props.children;

Continuing with the component, change it to

import './Button.css'

function Button({ children, onClick }) {
    return <button type="button" className="button" onClick={onClick}>{children}</button>;
}

export default Button;

We now import a file called Button.css on the same folder as our component, to use a class for our button. We still use the children as the button text, but now we also allow a property called onClick to be passed to this component, and we set it as the onClick of our button.

We can pass a function to this Button component and it will be called when the button is pressed.

Change the component usage to:

<Button onClick={function() {
        alert(1)
        }}>
        I'm the children of the button component
</Button>

Lastly, create a Button.css file with the following content

.button {
    background: rgb(216, 69, 253);
    color: white;
    padding: 8px 6px;
    border: none;
    outline: none;
    cursor: pointer;
    border-radius: 2px;
}   

.button:hover {
    background: rgb(120, 22, 199);
}

We are passing the onClick property with a function that calls an alert, you can save the file, and click on the button to show the alert.

Good! We have a button component, we can use it to pass a function to be called, and use its children as the text.

Creating a footer and cleaning our App.js

Create a new file named Footer.js, and a Footer.css for the style content.

Footer.js:

import './Footer.css'

function Footer() {
    return <footer className="footer">
        <ul>
            <li>
                <a href="https://en.wikipedia.org/wiki/Axolotl">Learn more about Axolotl on Wikipedia</a>
            </li>
            <li>
                <a href="https://github.com/AxolotlAPI">Axolotl API</a>
            </li>
            <li>
                <a href="https://www.nationalgeographic.com/animals/article/endangered-axolotls-conservation-mexico-city-chinampa">Axolotl on National Geographic</a>
            </li>
        </ul>
    </footer>;
}

export default Footer;

Footer.css content:

.footer {
    background: rgb(58, 59, 117);
    min-height: 150px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.footer ul {
    list-style-type: none;
    margin: 0;
    padding: 0;
}

.footer li {
    float: left;
    margin: 0 1rem;
}

.footer a {
    color: white;
}

.footer a:hover {
    background: black;
}

As you can notice, our Footer component has no props and doesn't even use the children prop, so using it is as simple as <Footer/>

Going back on App.js, let's clean it:

import Footer from './Footer';

function App() {
  return (
    <div>
      <Footer/>
    </div>
  );
}

export default App;

It now only renders our Footer component inside a div. You can see it live after saving! This component doesn't introduce anything new, you can change it as you want, modifying the links or adding more.

The Image component

The image component has props but it is trivial, just a wrapper around the img element.

Create an Image.js, with the following content:

function Image({ src, className }) {
    return <img className={className} src={src}/>;
}

export default Image;

We are passing a prop called className and using it on the className itself for the img element, this way the parent component that has this Image component can define its style.

The Fact component

This component has all the logic for our App! It has the responsibility of getting the data from the API and showing it, the App component or the Button component doesn't care about it.

Create a Fact.js and a Fact.css file

Fact.js:

import './Fact.css'
import Button from './Button'
import Image from './Image'

function Fact() {
    return <section className="fact">
        <Image className="img" src='https://picsum.photos/200'/>
        <h2>This will become data from our API</h2>
        <Button>Give me a new fact</Button>
    </section>;
}

export default Fact;

Fact.css:

.fact {
    text-align: center;
    width: 100%;
    margin: 1rem;
}

.fact h2 {
    font-size: 1.44rem;
    font-weight: bold;
}

.img {
    width: 25vw;
    min-width: 200px;
    border-radius: 4px;
}

The component currently has no logic, the only thing it does is show a placeholder image, with a button that does nothing. Up to this point, the component doesn't introduce anything that the others didn't have.

Loading API data into the Facts component

We need a way to request the Axolotl API for a random fact, we will do this with a React Hook.

A React Hook defines code hooked into our component, being executed only when certain dependencies are met.

Code outside hooks and inside our component is executed every time the Component renders, and that is not what we want, when our component loads, we want to request the API once.

Change the Fact.js file:

import React from 'react'
import './Fact.css'
import Button from './Button'
import Image from './Image'

const axolotlData = [
    {url: "https://i.redd.it/h49jxatnq6a71.jpg", facts: "Our breeding season typically runs from March to June."},
    {url:"https://i.imgur.com/TZENOci.jpg", facts: "The males often grow longer than the females, but not always."},
    {url:"https://i.redd.it/k6r62vtnq6a71.jpg", facts: "Axolotls have very few predators."},
];

function fetch() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve({json: () => axolotlData[Math.floor(Math.random() * axolotlData.length)]});
        }, 100);
    });
}

function Fact() {
    React.useEffect(() => {
        const loadFact = function() {
            fetch('https://axoltlapi.herokuapp.com/')
                .then(response => response.json())
                .then(data => {
                    console.log(data)
                })
        }
        loadFact();
    }, [])

    return <section className="fact">
        <Image className="img" src='https://picsum.photos/200'/>
        <h2>This will become data from our API</h2>
        <Button>Give me a new fact</Button>
    </section>;
}

export default Fact;

I learned that the API on https://axoltlapi.herokuapp.com/ will block our requests(because something called CORS), so we can't use it...

There is a variable called axolotlData above, with a list of objects containing the URL of an image and facts about Axolotl, this data is originally from the API.

Below that, a function fetch is declared, we are simulating an API call there, it returns a random fact from the pre-defined list after 100 milliseconds.

And finally, below there is our Fact component, which is now using a React Hook, the hook uses a function that we define, and a list of dependencies. We listed no dependencies on this hook, as an empty array [], this will make the component run this code once, if we didn't have this empty list, or the code was outside the hook, it would be called at each render.

By checking the App, you will see that nothing different happens, except it does... open the dev tools of your browser by pressing F12 on the App page, and go to the Console tab, you will see that random data is logged there every time the component mounts.

Using state on our component

We can't display data yet, we need a way to store this data.

This is how we will use state:

  • When we receive the data, we set our state to match that data
  • When we change our component state, it is rendered again, so we store data in it that is relevant to what is being shown on the screen, in this case, the picture URL and the Axolotl fact
  • Our state will remain the same until we set it again to a new value

Change the Fact component:

function Fact() {
    const [ data, setData ] = React.useState({ url: '', facts: ''});

    React.useEffect(() => {
        const loadFact = function() {
            fetch('https://axoltlapi.herokuapp.com/')
                .then(response => response.json())
                .then(data => {
                    setData(data)
                })
        }
        loadFact();
    }, [])

    return <section className="fact">
        <Image className="img" src={data.url}/>
        <h2>{data.facts}</h2>
        <Button>Give me a new fact</Button>
    </section>;
}

There is only one line being added, and some changes, what they are doing?

const [ data, setData ] = React.useState({ url: '', facts: ''});

This is using the state hook to define a state with the default value of { url: '', facts: ''}, the hook returns an array with two elements, the first one is the current value of the state, and the second one is a function to set the state, the names doesn't matter. The destructuring we saw earlier is being used here.

setData(data)

We changed console.log to setData, when this function is called, the state is updated and our component renders again.

<Image className="img" src={data.url}/>
<h2>{data.facts}</h2>

We now show data from the state on our component.

Giving a function to our button

We already have the function that gets the data and updates our state, adding logic to our button now is only a matter of decoupling that function from our hook.

function Fact() {
    const [ data, setData ] = React.useState({ url: '', facts: ''});

    const loadFact = function() {
        fetch('https://axoltlapi.herokuapp.com/')
            .then(response => response.json())
            .then(data => {
                setData(data)
            })
    }

    React.useEffect(() => {
        loadFact();
    }, [])

    return <section className="fact">
        <Image className="img" src={data.url}/>
        <h2>{data.facts}</h2>
        <Button onClick={loadFact}>Give me a new fact</Button>
    </section>;
}

Our loadFact function now is declared on every render, we call it once our component is mounted due to our hook, and we call it every time the button is clicked because we pass it to the onClick property.

Neat! Our Axolotl App is fully functional.

If the data doesn't change when clicking the button a few times, it's because we are getting random data from a list with 3 values, and it repeats sometimes.

More information

This guide attempts to be easy to understand, if you think something could be worded better, is wrong, or should be changed, contact us.

Below are some notes:

  • You can see some () => in the code, and some function (), they are almost the same! The arrow syntax goes unmentioned through this tutorial, while function is used in more noticeable places.
  • Some things are left unexplained, Create React App is doing a lot of things under the hood, which it's not mentioned, if you feel overwhelmed by not knowing what is going on, you can set up a React app without it, and see the limitations and understand what and why certain things are being done in Create React App(CRA).

Learning resources

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Can Linux read NTFS? 6 things to know about Linux and NTFS

useState, useEffect, useCallback, useMemo, and more: React Hooks explained with examples