Skip to main content

Command Palette

Search for a command to run...

Using React useState hook with an api call

Updated
•8 min read•View as Markdown
Using React useState hook with an api call

Hi all, this is a quick introduction to the react hook useState and how to use it in the simple context of functional React and an API call (async). It's part #1 of a 7-part group of articles on React hooks and how I learned them while building a simple app.

When you're a new React learner, it can be hard to find examples and tutorials that help you for your specific needs. So I thought I'd share my react practice in case that helps anyone out there :)

1 - The React useState hook

When I was looking into how to use React useState hook, I found basic examples but I also wanted to build something that did more than just add to a counter. Nothing wrong with a counter, but I wanted my first attempt to be a bit more interesting and maybe have an api call in it, so I decided to build a simple call to the github API, where I would provide a username and the API would return a list of their public repos. I would display the list of repos and I would be able to select one from the list and see more info about it.

This means that my page is organised in 3 main parts:

  • a simple form with an input field where I enter a username and submit it
  • a section where I display the list of repos I get back from the api
  • a section where I display a specific repo when selected from the repo list

In the below sections, we will go into details describing each part of code needed to achieve this. Or if you want to skip right to the code, you can go check it out on my repo react-state. It's not styled at all so it doesn't look pretty, but you can check out the code, and maybe even clone it and play with it if you like :)

First steps

For the rest of this article, and especially if you are coding along, we'll assume that the following is already in place:

  • we have a basic React app set up with create-react-app.
  • we have a component/page set up and it is called in App.js. For example:
    function App() {
    return (
      <>
        <GithubRepo />
      </>
    );
    }
    
  • we have a function set up in our component and it is returning a basic display. For example:
    export const GithubRepo = () => { 
    ...
    return <> ... </>
    }
    
  • we have imported the useState hook at the top of our component js file
  • we are familiar with JavaScript and some of its core concepts, including function expressions, ternary operator syntax and array and object methods.

Setting up the variables

From the description in the intro, we know that there are 3 things (or states) we need to track on the page: the username, the repo list and the selected repo. To track these 3 variables, we can set up the following states:

 const [username, setUsername] = useState("");
 const [repos, setRepos] = useState();
 const [selectedRepo, setSelectedRepo] = useState();

Each state is declared in the following way:

const [variable, function] = useState(initialValue)

where:

  • the "variable" is what we want to track and where we will store data, and can be given any name that makes sense with the app/page.
  • the "function" is generally named "set + your variable name" and will be called when we want to update the variable to a new value.
  • the "initialValue" is the value we want for our variable on page load. For example, I want my username field to display nothing on load so I have set its original value to be an empty string.

Linking the username variable to the form element

What we want to be able to do is track what the user types and save it into the username state variable so this can be passed to a function on submission of the form. To achieve it, we can track the changes made to the input field and update the username variable when a change is made. Setting this up would be in 3 parts that look like this:

  1. A simple form with an input field and a submit button:

    <form onSubmit={onSubmit}>
         <input
           id="search-input"
           value={username}
           placeholder="Enter github username"
           onChange={handleChange}
         ></input>
         <button id="submit-btn">Search</button>
    </form>
    
  2. An onChange event on the input field to monitor the user's input, which calls the handleChange function:

    const handleChange = (event) => {
     setUsername(event.target.value);
    };
    

    This function updates the variable "username" with the content of the input field every time a letter is added/removed from the field. That way, the variable is always up to date, and for this reason, we also assign this variable as the display value of the input field by setting up: value={username}

  1. An onSubmit function that gets triggered on click of the search button:
    const onSubmit = (event) => {
     event.preventDefault();
     getRepos(username);
    };
    
    This function uses the variable "username" and passes it to the async function "getRepos" in charge of the github api call.

How to get the public repos using the github api?

This is an async call to an api. As we are in a React app (in the browser), and we are making that call with a button click on the form, we can use the fetch method (available with the browser) to do that. Setting up this function would look like this:

const getRepos = async (username) => {
    const response = await fetch(`https://api.github.com/users/${username}/repos`).then((response) => response.json());
    setRepos(response);
  };

We are passing the username in the URL template string. Once we have the response, we are updating the variable "repos" with it.

How to display the repos on the page

Once we have the list of repos, we can display it on the page by mapping through the repos variable. Setting up the list would look like this:

        <div>
          <h2>Search results</h2>
          {repos && repos.length ? (
            repos.map((item) => {
              return (
                <button
                  key={item.id}
                  id={item.id}
                  onClick={onRepoClick}
                >
                  {item.name}
                </button>
              );
            })
          ) : (
            <div> No repos </div>
          )}
        </div>

Here we are using a ternary operator to determine what is to be displayed:

  • if the variable "repos" is empty, for example on load of the page before a search is triggered or when the api response is empty, then we will display a simple "No repos" message.
  • if the variable "repos" contains an array of data, then we will loop through it with repos.map and return a simple button for each repo. As per React best practices, we make sure to set up a unique key for each button, and we also add an onClick event which will allow us to click a repo and see more details later on.

How to get details for a selected repo

So we know that we created that list of repos as buttons, each with a onClick event. To get the info of the selected repo, we will extract the info of that repo from the repos array based on the button id we just clicked, and then save it in the variable "selectedRepo". Setting up the function would look like this:

const onRepoClick = (event) => {
    const selection = repos.filter((item) => item.id === parseInt(event.target.id))[0];
    setSelectedRepo(selection);
  };

Here we are filtering the repos to extract the targeted one. Once we have it, we update the variable "selectedRepo" with it.

Note: There are many other ways to extract the data, and probably much cleaner and more efficient ones.

How to display the details of the selected repo

Once we have those details in the selectedRepo state variable, we can pass it to the relevant element on the page. For example:

<div>
          <h2>Details for this repo</h2>
          {selectedRepo && (
            <>
              <h3>{selectedRepo.name}</h3>
              <h3>Last updated: {selectedRepo.updated_at}</h3>
              <h3>URL: {selectedRepo.url}</h3>
            </>
          )}
</div>

Here we are using a ternary operator to display details only when the selectedRepo state variable is not empty. Note: The 3 fields shown in the above example are just a suggestion, there are many other fields that could be displayed.

Going further

So maybe, like me, you think that the page looks a bit empty on load, because there's no list of repos and of course no selectedRepo yet. An option is to set up an initial search triggered on load with a set username, for example my own. That means that when opening the page, I would be automatically presented with my list of repos.

To make this happen, we can use another React hook: useEffect!

This hook is set up in such a way that it can monitor an item on the page and trigger an action when the monitored item changes. The base syntax is as follow:

useEffect(() => {
    ***some actions to execute***
  }, []);

where the first argument is the function containing the steps to execute and the second argument is the items to monitor. Here there are no items to monitor ([]) as we want the useEffect to be run only once on load of the page.

To get my repos on load, I can pass my username to the function like this:

 useEffect(() => {
    getRepos("am0031");
  }, []);

This would return all my public repos on load of the page, and store them in the repos state variable (as per the getRepos function).

If we wanted, we could go even further and have the first repo set up as the selectedRepo. For that, we could add to our useEffect function so that more actions are taken. I've not gone that far in my set up, but feel free to give it a go and see if you can make it work :)

The complete code for this exercise is available on my github repo react-state. It's not styled at all so it doesn't look pretty, but you can check out the code, and maybe even clone it and play with it if you like :)

In the next article, we'll talk about useEffect in more depth and add some useEffect hooks to this app :)