I would like to run customFunction
only when customEffect
has finished setting isReady
state. And customFunction
should only run once no matter if the isReady
was set to false
or true
as long as it was ran after it was set.
import customFunction from 'myFile';
export const smallComponent = () => {
const [isReady, setIsReady] = useState(false);
useEffect(() => {
const customEffect = async () => {
try {
const response = await get(
`some-api.com`,
);
return setIsReady(response); // response can be true or false
} catch {
return null;
}
};
customEffect();
customFunction();
}, []);
return (
<>Hello World</>
)
}
I tried to add isReady as second useEffect argument, but then my customFunction is being run before the customEffect finishes and then again after the isReady is being set.
Also tried having in a separate useEffect, but still seems to run before the customEffect finishes.
Since you want to cue an effect to run after the isReady
state is set, and the value of isReady
is irrelevant you can to use a second state value to indicate the first effect and state update has completed.
This will trigger the second effect to invoke customFunction
but you don't want your component to remain in this state as from here any time the component rerenders the conditions will still be met. You'll want a third "state" to indicate the second effect has been triggered. Here you can use a React ref to indicate this.
export const smallComponent = () => {
const [readySet, setReadySet] = useState(false);
const [isReady, setIsReady] = useState(false);
const customFunctionRunRef = useRef(false);
useEffect(() => {
const customEffect = async () => {
try {
const response = await get(
`some-api.com`,
);
setReadySet(true); // to trigger second effect callback
return setIsReady(response); // response can be true or false
} catch {
return null;
}
};
customEffect();
}, []);
useEffect(() => {
if (readySet && !customFunctionRunRef.current) {
// won't run before readySet is true
// won't run after customFunctionRunRef true
customFunction();
customFunctionRunRef.current = true;
}
}, [readySet]);
return (
<>Hello World</>
);
}
Better solution borrowed from @p1uton. Use null isReady
state to indicate customFunction
shouldn't invoke yet, and the ref to keep it from being invoked after.
export const smallComponent = () => {
const [isReady, setIsReady] = useState(null);
const customFunctionRunRef = useRef(false);
useEffect(() => {
const customEffect = async () => {
try {
const response = await get(
`some-api.com`,
);
return setIsReady(response); // response can be true or false
} catch {
return null;
}
};
customEffect();
}, []);
useEffect(() => {
if (isReady !== null && !customFunctionRunRef.current) {
// won't run before isReady is non-null
// won't run after customFunctionRunRef true
customFunction();
customFunctionRunRef.current = true;
}
}, [isReady]);
return (
<>Hello World</>
);
}
Set initial value to null
and use separate useEffect
as Kevin suggested (only without checking isReady
true/false).
In this case setIsReady
will change isReady
from null to true/false and the second useEffect
will be called.
import customFunction from 'myFile';
export const smallComponent = () => {
const [isReady, setIsReady] = useState(null);
useEffect(() => {
const customEffect = async () => {
try {
const response = await get(
`some-api.com`,
);
return setIsReady(response);
} catch {
return null;
}
};
customEffect();
}, []);
useEffect(() => {
if (null === isReady) {
return;
}
customFunction();
}, [isReady]);
return (
<>Hello World</>
)
}
I'm not sure if I understood you correctly, but this is how I would use a separate useEffect
.
import customFunction from 'myFile';
export const smallComponent = () => {
const [isReady, setIsReady] = useState(false);
useEffect(() => {
const customEffect = async () => {
try {
const response = await get(
`some-api.com`,
);
return setIsReady(response);
} catch {
return null;
}
};
customEffect();
}, []);
useEffect(() => {
if (!isReady) {
return;
}
customFunction();
}, [isReady]);
return (
<>Hello World</>
)
}
Have you tried using this package, isMounted ?
I used that in my projects.
import React, { useState, useEffect } from 'react';
import useIsMounted from 'ismounted';
import myService from './myService';
import Loading from './Loading';
import ResultsView from './ResultsView';
const MySecureComponent = () => {
const isMounted = useIsMounted();
const [results, setResults] = useState(null);
useEffect(() => {
myService.getResults().then(val => {
if (isMounted.current) {
setResults(val);
}
});
}, [myService.getResults]);
return results ? <ResultsView results={results} /> : <Loading />;
};
export default MySecureComponent;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.