Reputation: 4327
I have a custom hook useWebApi
, which can call a web api and return the api result.
function useWebApi(method, url) {
const [fetching, setFetching] = useState(true);
const [result, setResult] = useState(null);
useEffect(() => {
axios[method](url).then(res => {
setFetching(false);
setResult(res);
})
}, [url]);
return [fetching, result];
}
and I want to do something like, fetch url1
, if url1
is fetched, then fetch url2
. The two apis are not independent, url2
can only be called when url1
finish fetching.
so I write the code like below
const url1 = '/login';
const url2 = '/getMyUserInfo';
function App() {
const [fetching1, result1] = useWebApi('get', url1);
if (result1) {
const [fetching2, result2] = useWebApi('get', url2);
}
return (
<div>
{result1}
{result2}
</div>
)
}
but hook can not be called inside if
statement, so I change it to,
const url1 = '/login';
const url2 = '/getMyUserInfo';
function App() {
const [fetching1, result1] = useWebApi('get', url1);
useEffect(() => {
if (result1) {
const [fetching2, result2] = useWebApi('get', url2);
}
}, [result1])
return (
<div>
{result1}
{result2}
</div>
)
}
but, there are still problems, I can not render result2
, because it is inside a nested scope, so how do I fix it ?
Upvotes: 1
Views: 2085
Reputation: 89
I know this is an old question, but someone might bump into it in the future and it seems to me that none of the answers solve the general problem here (e. g. how to call a react hook when its input is the output of a previous hook).
Don't get me wrong, the answers provided above are good solutions for this particular problem, but can't be applied as a rule.
The solution to the general problem of cross-dependent hook is dividing your component into multiple components and using return statements conditionally.
Firstly implement a new InnerComponent
, that is going to take the result of your first api call as a prop.
const url2 = '/getMyUserInfo';
export function InnerComponent() {
const [fetching, result] = useWebApi('get', url2);
return <>{ result }</>
}
Then render this new component conditionally, this is allowed.
const url1 = '/login';
import { InnerComponent } from './InnerComponent'
function App() {
const [fetching, result] = useWebApi('get', url1);
if (fetching) {
return 'Loading...' // Or some actual Loader component
}
return (
<div>
{result}
{ result && <InnerComponent /> } // Here you can be sure that the result of the first hook call is obtained
</div>
)
}
Upvotes: 2
Reputation: 595
You could maybe move the condition in to your hook:
function useWebApi(method, url, flag = true) {
const [fetching, setFetching] = useState(true);
const [result, setResult] = useState(null);
useEffect(() => {
if(flag) {
axios[method](url).then(res => {
setFetching(false);
setResult(res);
})
}
}, [url, flag]);
return [fetching, result];
}
function App() {
const [fetching1, result1] = useWebApi('get', url1);
const [fetching2, result2] = useWebApi('get', url2, !!result1);
return (
<div>
{result1}
{result2}
</div>
)
}
Upvotes: 0
Reputation: 10873
What you could do is to expose a doFetch
method, etc. that will enable calling the hook manually.
function useWebApi(method, url) {
const [fetching, setFetching] = useState(true);
const [result, setResult] = useState(null);
const doFetch = useCallback((fetchUrl = url) => {
axios[method](fetchUrl).then(res => {
setFetching(false);
setResult(res);
})
}, [method, url])
useEffect(() => {
if (url) {
doFetch();
}
}, [doFetch]);
return [fetching, result, doFetch];
}
function App() {
const [fetching1, result1, doFetch1] = useWebApi('get', url1);
const [fetching2, result2, doFetch2] = useWebApi('get');
useEffect(() => {
if (result1) {
doFetch2(url2);
}
}, [result1])
return (
<div>
{result1}
{result2}
</div>
)
}
Upvotes: 3
Reputation: 202761
If the second call is not dependent on the result value of the first (i.e. they are two independent GET requests) then go ahead and call them both at the top level as expected of hooks and selectively render result two only if result one exists.
function App() {
const [fetching1, result1] = useWebApi('get', url1);
const [fetching2, result2] = useWebApi('get', url2);
return (
<div>
{result1}
{result1 ? result2 : null}
</div>
)
}
Upvotes: 0