DEV Community

Mario
Mario

Posted on • Originally published at mariokandut.com on

How to trigger data fetching with React hooks?

In many applications fetching data is done by triggering a React hook programmatically or manually. This article gives an example on how to do this. The used example is from the previous article How to fetch data with react hooks, below is the code:

import React, { useState, useEffect } from 'react';

function App() {
  const [data, setData] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      const res = await fetch(
        'https://hn.algolia.com/api/v1/search?query=react',
      );
      const json = await res.json();
      setData(json.hits);
    };
    fetchData();
  }, []);

  return (
    <ul>
      {data.map(item => (
        <li key={item.ObjectId}>
          <a href={item.url}>{item.title}</a>
        </li>
      ))}
    </ul>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Fetch data programmatically with useEffect

The above example fetches data when the component mounts. We are always fetching the exact same query "react". Let's add an input element to fetch other stories. Therefore, we have to add an input field, a state for the search query from the input field and update fetchData to use this dynamic search query.

import React, { useState, useEffect } from 'react';

function App() {
  const [data, setData] = useState([]);
  const [query, setQuery] = useState('react');

  useEffect(() => {
    const fetchData = async () => {
      const res = await fetch(
        `https://hn.algolia.com/api/v1/search?query={query}`,
      );
      const json = await res.json();
      setData(json.hits);
    };
    fetchData();
  }, []);

  return (
    <React.Fragment>
      <input
        type="text"
        value={query}
        onChange={event => setQuery(event.target.value)}
      />
      <ul>
        {data.map(item => (
          <li key={item.ObjectId}>
            <a href={item.url}>{item.title}</a>
          </li>
        ))}
      </ul>
    </React.Fragment>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

One last thing. Try to update the code and run it. Did you notice something? When you type in the input field, the search is not triggering the fetchData(). The reason is that the useEffect hook does not depend on anything. The second argument of useEffect is an empty array, so it is only triggered once when the component mounts. The effect should run, when the search query changes. Hence, we have to provide the query as the second argument.

import React, { useState, useEffect } from 'react';

function App() {
  const [data, setData] = useState([]);
  const [query, setQuery] = useState('react');

  useEffect(() => {
    const fetchData = async () => {
      const res = await fetch(
        `https://hn.algolia.com/api/v1/search?query={query}`,
      );
      const json = await res.json();
      setData(json.hits);
    };
    fetchData();
  }, [query]);

  return (
    <React.Fragment>
      <input
        type="text"
        value={query}
        onChange={event => setQuery(event.target.value)}
      />
      <ul>
        {data.map(item => (
          <li key={item.ObjectId}>
            <a href={item.url}>{item.title}</a>
          </li>
        ))}
      </ul>
    </React.Fragment>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Now on every change of the input field data is fetched. What if we want to add a Search button to avoid fetching on every key stroke?

Fetch data manually with useEffect

To avoid fetching data on every change of the query state, we can simply add a button to trigger fetchData(). Let's try it. We add a button with an onClick method to set a new state search, which triggers the useEffect hook.

import React, { useState, useEffect } from 'react';

function App() {
  const [data, setData] = useState([]);
  const [query, setQuery] = useState('react');
  const [search, setSearch] = useState('react');

  useEffect(() => {
    const fetchData = async () => {
      const res = await fetch(
        `https://hn.algolia.com/api/v1/search?query={query}`,
      );
      const json = await res.json();
      setData(json.hits);
    };
    fetchData();
  }, [search]);

  return (
    <React.Fragment>
      <input
        type="text"
        value={query}
        onChange={event => setQuery(event.target.value)}
      />
      <button onClick={() => setSearch(query)}>Search</button>
      <ul>
        {data.map(item => (
          <li key={item.ObjectId}>
            <a href={item.url}>{item.title}</a>
          </li>
        ))}
      </ul>
    </React.Fragment>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Well, now it works. Somewhat. We have two states to manage the search query. We have to refactor the code to remove duplication. Instead of setting an additional search state, which is the same as the query state, we can just provide the url with the query to fetch.

import React, { useState, useEffect } from 'react';

function App() {
  const [data, setData] = useState([]);
  const [query, setQuery] = useState('react');
  const [url, setUrl] = useState(
    'https://hn.algolia.com/api/v1/search?query=react',
  );

  useEffect(() => {
    const fetchData = async () => {
      const res = await fetch(url);
      const json = await res.json();
      setData(json.hits);
    };
    fetchData();
  }, [search]);

  return (
    <React.Fragment>
      <input
        type="text"
        value={query}
        onChange={event => setQuery(event.target.value)}
      />
      <button
        onClick={() =>
          setUrl(`https://hn.algolia.com/api/v1/search?query={query}`)
        }
      >
        Search
      </button>
      <ul>
        {data.map(item => (
          <li key={item.ObjectId}>
            <a href={item.url}>{item.title}</a>
          </li>
        ))}
      </ul>
    </React.Fragment>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

That's if for the implicit programmatic data fetching with useEffect. You can decide on which state the effect depends. Once you set this state, the useEffect will run again. In this case, if the URL state changes, the effect runs again to fetch data from the API.

TL;DR

💰: Start your cloud journey with $100 in free credits with DigitalOcean!

Thanks for reading and if you have any questions , use the comment function or send me a message @mariokandut.

If you want to know more about React, have a look at these React Tutorials.

References (and Big thanks):

ReactJS, Robin Wieruch, Dave Ceddia

Top comments (0)