How to Make API Call with Hooks in React

Where can I make API call with hooks in react?

Yes, there's a similar (but not the same!) substitute for componentDidMount with hooks, and it's the useEffect hook.

The other answers don't really answer your question about where you can make API calls. You can make API calls by using useEffect and passing in an empty array or object as the second argument as a replacement for componentDidMount(). The key here is the second argument. If you don't provide an empty array or object as the second argument, the API call will be called on every render, and it effectively becomes a componentDidUpdate.

As mentioned in the docs:

Passing in an empty array [] of inputs tells React that your effect doesn’t depend on any values from the component, so that effect would run only on mount and clean up on unmount; it won’t run on updates.

Here are some examples for scenarios where you will need to make API calls:

API Call Strictly on Mount

Try running the code below and see the result.

function User() {  const [firstName, setFirstName] = React.useState(null);  const [lastName, setLastName] = React.useState(null);    React.useEffect(() => {    fetch('https://randomuser.me/api/')      .then(results => results.json())      .then(data => {        const {name} = data.results[0];        setFirstName(name.first);        setLastName(name.last);      });  }, []); // <-- Have to pass in [] here!
return ( <div> Name: {!firstName || !lastName ? 'Loading...' : `${firstName} ${lastName}`} </div> );}
ReactDOM.render(<User />, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script><script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>

how to make api calls in reactjs new hook api and share that across components?

You can create a custom hook that creates a new piece of state advice that you set when your network request has finished.

Return a function from the function given to useEffect that cancels your request when the component that uses it re-renders or the component is unmounted. You can also give your url in an array as the second argument to useEffect to only re-run the network request when the url actually changes.

Example

const { useState, useEffect } = React;
function useAdvice(url) { const [advice, setAdvice] = useState(null);
useEffect( () => { const timeout = setTimeout(() => { setAdvice(`Use ${url} to get some nice advice`); }, 1000); return () => clearTimeout(timeout); }, [url] );
return advice;}
function App() { const advice = useAdvice("https://google.com");
return <div>{advice}</div>;}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.production.min.js"></script><script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.production.min.js"></script><div id="root"></div>

React - API call within useEffect or not

Ideally,

if you want to make an API call on click of a button there is no need to use any hook like useEffect and useState, the way you did. your second approach is perfect and there is nothing wrong with that.

But if there is some specific usecase where it is required then there is nothing wrong in using hooks also you will just be making some extra rerenders but if that serves your use case then I guess that is fine too.

note:

<button onClick={setTrigger(true)}>Click me</button>

this is wrong, this setTrigger function will be call on mount of the component and I guess you might not want that.

you can instead do

<button onClick={()=>setTrigger(true)}>Click me</button>

OR

const MyComponent = () => {
const [myState, setMyState] = useState([])

const getData = async () => {
const callMyApi = await fetch('http://someApi.com')
setMyState(await callMyApi.json()
}

return (
<button onClick={getData}>Click me</button>
)
}

React, make a second API call based on a state set by a first api call

What you are missing is that when you are calling searchFollowing(), React did not yet re-render, therefore location wouldn't be updated. You could have an useEffect that would listen to location, and call searchFollowing() there when location.lat and location.lon are defined:

useEffect(()=>{
if(location.lat && location.lon){
searchFollowing();
}
}, [location])

Then remove searchFollowing() call inside search function, as now you call it inside the above useEffect.

Access API response data from a custom React hook

React doesn't guarantee that the state will be immediately updated after setState(). This is because state updates are non-blocking which means that code execution within the click handler will not wait for the state update to finish. Even if you try using await with the API_REQUEST(), it will still not immediately reflect. State updates will be added to the task queue and the code will continue executing past this point, therefore when it reaches the if statement, the data will not be up to date at this point.

In old class component days, we could pass a callback to setState() as a second argument which would allow us to do anything with upto date state.

this.setState(counter => counter + 1, updated => console.log(updated));

But with functional components, we can no longer do this and React docs recommend using effect hooks. Therefore, you have to implement a similar behavior yourself if you need it, by adding some kind of callback to your custom hook, that will be run when the API request is made. It could be done using useEffect() inside your custom hook.

You can make the useEffect() run only after data has changed by adding only data as a dependency:

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

How to avoid useEffect()?

However, as you said you only want this to run on click and the above doesn't tell how the data actually changed. So we have to think outside the box here i.e. do we really need to take the data from the state? I think we can take the data by passing a callback as a second argument to API_REQUEST() and bypass state:

useAxios.js

import { useEffect, useState } from "react";

const useAxios = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [data, setData] = useState(null);
const [controller, setController] = useState();

const API_REQUEST = async (config, callback) => {
const { AxiosInstance, method, url, requestConfig } = config;

try {
setLoading(true);
setError(null);
setData(null);
const ctrl = new AbortController();
setController(ctrl);

const response = await AxiosInstance({
method,
url,
...requestConfig,
signal: ctrl.signal
});
setData(response.data);
callback(response.data);
} catch (error) {
console.error({ error });
setError(error.message);
} finally {
setLoading(false);
}
};

useEffect(() => {
return () => controller && controller.abort();
}, [controller]);

return { loading, error, data, API_REQUEST };
};

export default useAxios;

Now you may use API_REQUEST() like this:

API_REQUEST(
{
AxiosInstance: axios,
method: "get",
url: "/todos",
requestConfig: {}
},
(responseData) => console.log(responseData)
);

Here is a working example: https://codesandbox.io/s/api-request-callback-q40bxr

How to execute a function AFTER an API-Call was made with setState within useEffect?

You can just add control to your second useEffect, it will solve your issue. This is working sample https://codesandbox.io/s/heuristic-matan-3kdbmv

React.useEffect(() => {
if (allMemes.length > 0) {
getMemeImage();
}
}, [allMemes]);

Trying to make an API call before using setInterval() in useEffect() hook in React

the important thing to note here is that your updateData function should return a promise to make await work then your above logic will work perfectly. It will wait until the first API call is not finished before going to the second line.

    useEffect(() => {
await updateData(id, state, setState);
const interval = setInterval(async () => {
if (id) {
await updateData(id, state, setState); // API call
}
}, 5000);


//update function would be like:
function updateData(id, state, setState) {
...
return API.get("/url");
}
}, []);

How to instantly display data after an API call in react hooks

You don't need stateCopy, as you have it in the callback of the setState:

const setInfo = async () => {
// we want to update the component only once
const results = await Promise.all(
state.map(item => getFetch(item.steamId))
);
// 's' is the current state
setState(s =>
results.map((res, index) => ({ ...s[index], date: res.Date })
);
};


Related Topics



Leave a reply



Submit