How to Call Loading Function with React Useeffect Only Once

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



Leave a reply



Submit