Fetching Data From An API With a Button onClick Event Handler In React

August - 2021

TODO: Combine these two posts into one (or eliminate one if they are duplicates)

/fetching-data-from-an-api-with-a-button-onclick-event-handler-in-react-2 /fetching-data-from-an-api-with-a-button-onclick-event-handler-in-react


This is how I'm fetching data from a remote API via a button's onClick event handler in React.

<!DOCTYPE HTML>
<html>
<head>
    <title>Fetching Remote Data With A Button Click And Error Handling</title>  
    <script src="https://unpkg.com/react@16.12.0/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/@babel/standalone@7.8.3/babel.js"></script>
<style>
body { background-color: #555; }
</style>

</head>
<body>
    <p>Fetching Remote Data With A Button Click</p>
    <p><a href="/">Home</a></p>
    <div id="root"></div>
    <script type="text/babel">
        function App() {
            const [statusMessage, setStatusMessage] = React.useState('TBD')
            const [isFetching, setIsFetching] = React.useState(false)

            React.useEffect(() => {
                if (isFetching) {
                    window.fetch('https://api.weather.gov/')
                        .then(response => response.json())
                        .then(
                            response => {
                                setStatusMessage(response.status)
                            },
                            errorData => {
                                setStatusMessage('ERROR')
                            }
                        )
                    setIsFetching(false)
                }
            })

            return (
                <div>
                    <div>API Status: {statusMessage}</div>
                    <button onClick={() => setFetchStatus('pending')}>Check Status</button>
                </div>
            )
        }

        ReactDOM.render(<App/>, document.getElementById('root'))
    </script>
</body>
</html>

Notes:

  • This example uses unpkg.com to call versions of react and babel to make it stand alone, but the script will function in a regular React app.
  • In a regular app, you'd use <script type="text/javascript"></script> instead of <script type="text/babel"></script>.
  • The thing that took me the longest to figure out was how to do the trigger itself. I setup a state object that gets updated when the button is pushed which causes a re-render of the component. When that happens, the useEffect sees the new state and fires off the fetch. When it's done, it updates the data and returns the state of pageFetchInProgress to false.
  • If the component is re-rendered while "pageFetchInProgress" is false, it doesn't pull the page again.
  • While the value is true, it pulls on every re-render. So, if something else causes a re-render while it was fetching, it would fetch again. You could put in another state variable to watch for this and prevent it from happening.

And here's another example from NMeuleman (it's setup in a more traditional way than scalling the script directly so it looks a little different). This one doesn't use a true/false switch.

import "./styles.css";
import { useState } from "react";

export default function App() {
  const [statusMessage, setStatusMessage] = useState("TBD");

  const fetchData = () => {
    fetch("https://api.weather.gov/")
      .then((response) => response.json())
      .then((response) => {
        setStatusMessage(response.status);
      })
      .catch(() => {
        setStatusMessage("ERROR");
      });
  };
  return (
    <div className="App">
      <div>API Status: {statusMessage}</div>
      <button onClick={fetchData}>Check Status</button>
    </div>
  );
}