How to call loading function with React useEffect only once
If you only want to run the function given to useEffect
after the initial render, you can give it an empty array as second argument.
function MyComponent() {
useEffect(() => {
loadDataOnlyOnce();
}, []);
return <div> {/* ... */} </div>;
}
useEffect' not run only once
the initial state in redux and state in component is an empty array.
so I want to GET data from API. and I push it to redux's state. then I
useState it. I want to use useEffect because I want to update state
when I PUT the data and update local state after update.
Ok, so I've gathered that you want fetch the data when the component mounts, and then store the fetched data into local state when it is populated. For this you will want to separate out the concerns into individual effect hooks. One to dispatch the data fetch once when the component mounts, the other to "listen" for changes to the redux state to update the local state. Note that it is generally considered anti-pattern to store passed props in local state.
const {onGetGeneralInfo, generalInfo} = props;
const [data, setData] = useState(generalInfo);
// fetch data on mount
useEffect(() => {
onGetGeneralInfo();
}, []);
// Update local state when `generalInfo` updates.
useEffect(() => {
setData(generalInfo);
}, [generalInfo, setData]);
What's the better way to run function only for once, useEffect or just call the function in Hooks?
I would suggest reading about react's life cycle here. This is a basic concept and must be mastered.
Calling a function straight in the body can help with debugging (such as using console logs) but is not a good practice and will consume a lot of memory. If this function sets the state, it will create an infinite loop and break your code.
By rule of thumb, never call functions in the body of your component.
Any side effects should either run by user input (pressing a button, typing, etc..) or by useEffect when a state changes.
Take a look at this example:
const example = () => {
const [counter, setCounter] = useState(0);
const [text, setText] = useState('');
// Calling a function in the body runs it on every render
// And is considered a bad practice, as any state change
// Will cause it to run and consume memory
myfunction();
const myFunction =() => { console.log('this will run on every render')}
useEffect(() => {
//This useEffect acts as componentDidMount
//It will only run once when the component mounts, since
// the dependency array is empty
console.log('mount');
}, []);
useEffect(() => {
// This will run once on mount and every time
// count changes. Typical use of useEffect
// This won't run when text changes.
console.log('count up', count);
}, [count]);
return (
<>
<button onClick={() => setCounter(counter + 1)} >
Clicked {counter} times
</button>
<input
placeholder="Any text here"
value ={text}
onChange={(e) => {setText(e.target.value)}}
/>
</>
)
}
ReactJS: how to call useEffect hook only once to fetch API data
If I understand correctly, you want to mimic the "on component mounted" behaviour of regular class based react components via useEffect()
, so that the effect callback only fires once on the first render.
To achieve that behaviour, you can pass an empty array to the second argument of useEffect()
like so:
useEffect(() => {
loadMessages();
}, []); /* <-- add this */
The second array argument allows you to specify which prop
variables trigger the useEffect()
callback (if any) when their value(s) change.
By passing an empty array, this means that useEffect()
won't be triggered by any changes to input prop
variables and will in turn only ever be called once, during the first render.
For more information on this second argument, see this documentation and this documentation
Run useEffect only one when a special property changed
While adding dependencies array to the end of useEffect
(or any other hook...), each render if the value is not equal to the prev one, the hook will run again.
Because props.coordinates
is an object, and in JS objA != objA == true
, even if the properties didn't change, React can't know that.
My suggestion is to use the values themselves (assuming they're strings either numbers and so on)
useEffect(() => {
(async () => {
await callApi();
setLoader(false);
})()
}, [props.coordinates.lat, props.coordinates.lon]);
Another thing that you might encounter is setLoader(false)
will be called before callApi
will be finished, therefore added async behaviour to the hook
React useEffect() only run on first render with dependencies
The way I handle this now is to put the appropriate dependencies in the list of dependencies.
Because I want the effect to run only one time, and because the effect only relies on some data when the component first mounts, it's perfectly fine to omit those dependencies. For example, the groups
prop may change later, but this effect doesn't need to run again.
But, as a habit I don't omit the recommended dependencies and I always list them. If I were to intentionally omit something, I would add an eslint ignore statement... it's whatever convention you want to follow as long as you understand what is happening when that data changes and the effect does / does not run.
However the code I proposed, shown below, isn't the best solution if you do want to list the dependencies as it causes an extra render when didLoad
changes.
const [didLoad, setDidLoad] = useState<boolean>(false);
useEffect(() => {
if (!didLoad) {
container.current = new VisTimeline(container.current, items, groups, options);
setDidLoad(true);
}
}, [didLoad, groups, items, options]);
Instead of using state to track that the effect ran, I will use a ref (which doesn't need to be a dependency).
const timelineLoaded = useRef<boolean>(false);
useEffect(() => {
if (!timelineLoaded.current) {
container.current = new VisTimeline(container.current, items, groups, options);
timelineLoaded.current = true;
}
}, [groups, items, options]);
Related Topics
Dangerous Implications of Allman Style in JavaScript
String.Replace' Weird Behavior When Using Dollar Sign ($) as Replacement
Merging or Combining Two Onedit Trigger Functions
Unexpected Behavior Using Array Map on an Array Initialized with Array Fill
JavaScript Variables Declare Outside or Inside Loop
How to Strip All Punctuation from a String in JavaScript Using Regex
Keyboard Shortcuts with Jquery
How to Count Certain Elements in Array
Call Multiple Functions Onclick Reactjs
How to Access a Numeric Property
Accessing Variables from Greasemonkey to Page & Vice Versa
Casting Plain Objects to Class Instances in JavaScript
Firebase: Setting Additional User Properties
Uncaught Typeerror: Illegal Invocation in JavaScript
What Does the @ Mean Inside an Import Path