Fetch data with useEffect Hooks programmatically/manually
Posted
Updated
Europe’s developer-focused job platform
Let companies apply to you
Developer-focused, salary and tech stack upfront.
Just one profile, no job applications!
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;
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;
💰 The Pragmatic Programmer: journey to mastery. 💰 One of the best books in software development, sold over 200,000 times.
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;
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?
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;
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;
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.
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.
Never miss an article.