Pulling Random Quotes from an API

I am wondering how to go about creating a data set of random quotes using an API. I have a list of websites that generate random quotes. I have tried to link to one of these websites and pull quotes with fetch(). My code is not logging any data to the console. Here is my code:

import React, { useEffect, useState } from "react";
import logo from "./logo.svg";
import "./App.css";

function App() {
  const [counter, setCounter] = useState(0);

  useEffect(() => {}, [counter]);

  const getQuotes = async () => {
    const response = await fetch(
      "https://api.whatdoestrumpthink.com/api/v1/quotes/"
    );
    const data = await response.json();
    console.log(data);
  };

  return (
    <div className="App">
      <form className="search-form">
        <input className="search-bar" type="text" />
        <button className="search-button" type="submit">
          Search
        </button>
      </form>
      <h1
        onClick={() => {
          setCounter(counter + 1);
        }}
      >
        {counter}
      </h1>
    </div>
  );
}

export default App;

The website I’m using gives this example:

Screen Shot 2019-12-19 at 14.18.10

Normally you can’t just throw function that fetches data into simple counter template and expect that everything will magically connect to each other :slight_smile:

Anyway, I think you forgot to invoke your getQuotes() function

Thanks for the help! And to your criticism - nothing was “just thrown” in anywhere. It seems that I was not far from success. I tried this using classes and things are working.

I am now logging data onto my console, but I have another problem - my data variable is not able to be used when rendering JSX because componentDidMount only creates the data variable after the page is rendered. I tried changing componentDidMount to componentWillMount but the variable data still cannot be accessed, although it logs on the console from inside the async await function. Anyone have any ideas how to access my data variable?

import React, { useEffect, useState, componentDidMount } from "react";
import logo from "./logo.svg";
import "./App.css";

class App extends React.Component {
  state = {
    loading: true,
    quoteData: ""
  };

  async componentDidMount() {
    const url = "http://quotes.stormconsultancy.co.uk/quotes/1.json";
    const response = await fetch(url);
    const data = await response.json();
    console.log(data);
  }

  render() {
    return (
      <div className="App">
        <h1>Random Quote Generation</h1>
        <div>{data}</div>
        <button
          onClick={() => {
            this.setState({ loading: true, quoteData: {data} });
          }}
        >
          Click For a Quote
        </button>
        <div>{this.state.quoteData}</div>
      </div>
    );
  }
}

export default App;

Try fetch on click and setState on successful fetch instead

Also note, as you will need to call fetch from 2 different places (onClick + componentDidMount) you might want to extract it as separate method

do I do this using async and await in the onClick? Or should I use some sort of conditional to check if fetch is completed? I can’t think of how to set a state key or prop to “successful” once the fetch is successful.

You can use try/catch for this:

async fetchData() {
  try {
    const response = await fetch(url);
    const data = await response.json();
    this.setState({
      loading: false,
      quoteData: data,
    });
  } catch (e) {
    console.error(e);
    this.setState({
      loading: false,
      quoteData: 'Oops! Couldn\'t fetch quote, please try again...',
    });
  }
}