Fetch API with useEffect

Hello everyone!
I’m trying to do a good practice in ReactJs fetching the date trought useEffect, but i have serious doubs about my code because I’m having some errors in console. Also, program still working fine despites console warnings.
First error: cannot read property ‘target’ of undefined.
Second and third error: in console says [violation] ‘message’ and ‘input’.

Anyone know what is the mistake? useEffects confuses me a litle but, I don’t know if its better wrap with the hook a function that fetch data. Or use useEffect as I’m currently using it.
By the way, I have to use preventDefault() in this case? It works fine without it.

I’m gonna leave some captures and a CodeSandBox with the code.

Thanks in advance!

CodeSandBox: https://codesandbox.io/s/busy-banzai-jcc69?file=/src/components/Add.js

Make sure you hide your GoogleApi keys

Read this doc it will help : https://codesandbox.io/docs/secrets#:~:text=Secrets%20are%20used%20to%20hide,be%20used%20in%20container%20sandboxes.

1 Like
useEffect(() => {
  }, [query])

What do you expect the above code to do. It runs after the initial render and whenever query changes. And the function, fetchData was not triggered by an element. So, e.target is undefined inside of it.

              placeholder="Search for a book"
              onChange={fetchData} // e.target is the input in this case

To add to what @samolex said, useEffect runs the effect (whatever is in the callback passed to useEffect) every time the component renders.

You are trying to execute the function fetchData when the “change” event fires on the input and when the value of query changes.

I didn’t know that, thanks a lot!

But I’m cofused about where I have to put setQuery, because I use Query for make changes, I can’t replace onChange={fetchData} for setQuery(e.target.value). Program works, but with console

…And that’s ok, use both?

The thing you’re misunderstanding here, and the thing that makes useEffect difficult to grok at first is that what it does is keep your component in sync.

What you’re trying to do there isn’t how it works at all.

So with your component, what you want to happen is that when the query state changes, run the effect (fetchData).

  onChange={(e) => setQuery(e.target.value)}

Do you see what this is doing? The value is whatever the query state is, when the value changes, set a new query state.

When the query state is changed, the component rerenders, and useEffect is ran again.

So move the fetchData function into the useEffect callback – it should not be where it is because that will cause things to go out of sync:

const [query, setQuery] = React.useState("");
const [result, setResult] = React.useState([]);

React.useEffect(() => {
  const fetchData = async () => {
    try {
      const req = await fetch(`https://www.googleapis.com/books/v1/volumes?q=${query}&key=AIzaSyDmmCThZovxSFYPvCUaUB6h4c5gYCJeUnw`;
      const resp = await req.json();
    } catch(err) {

  if (query !== "") fetchData();    
}, [query]);

And do you see how this is working? If query changes (and if it is not an empty string), make a fetch request that populates the result state. useEffect runs when the component first mounts, at which point query is "", so the fetch doesn’t run. Then if query changes, the component rerenders, and that useEffect (which depends upon the query variable) runs again and executes a fetch.

Thanks! you give a wonderful explanation. Thanks, again, for take your time for me. I read every line and you are right, my programs works better. I just so cofused, in part, because burnout. I see what is happend clearly now. I’m gonna read more about useEffect and async.

1 Like

It’s a hard thing to understand at first because the immediate temptation is to use like an event handler, and it doesn’t do that, it’s not at all like much else you’d have come across (and at the same time, it’s what you have to use to do some of the most common tasks).

Here’s a very long, very good guide to it:

1 Like