Using React, I have the following functional component where I make use of useEffect()
:
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
const MessagingComponent = React.memo(({ loadMessages, messages, ...props }) => {
useEffect(() => {
loadMessages();
});
return <div {...props}>These are the messages</div>;
});
const mapDispatchToProps = dispatch => ({
loadMessages: () => dispatch({ type: 'LOAD_MESSAGES' })
});
const mapStateToProps = state => {
return {
messages: state.chatt.messages.chatMessages
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(MessagingComponent);
As you can see, I have an effect callback that calls the loadMessages()
function in the useEffect()
callback in my MessagingComponent
:
useEffect(() => {
loadMessages();
});
The call to loadMessages()
loads messages which causes the component to re-render. This behaviour is as expected, however the problem is that the re-render causes the useEffect()
hook to fire again, which causes loadMessages()
to be called again. This in turn loads the messages from the back-end and causes the component to render again, and the cycle repeats.
How can I avoid this? Should I simply put an if condition in the useEffect()
hook, and check for the messages property?
Side Effect Runs Only Once After Initial Render You do not want to make this API call again. You can pass an empty array as the second argument to the useEffect hook to tackle this use case. useEffect(() => { // Side Effect }, []); In this case, the side effect runs only once after the initial render of the component.
Use the useEffect hook to only call a function once in React. When the useEffect hook is passed an empty dependencies array, it is only run when the component mounts. This is the preferred approach when you have to fetch data when the component mounts.
If your application is behaving strangely after updating to React 18, the default behavior of useEffect changed to run it 2 times. Just in development mode, but this is the mode everyone builds their application on.
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
useEffect()
is a react hook for functional components which covers the functionality of the lifecycle hooks of the class components. useEffect()
combines componentDidMount(), componentDidUpdate()
and componentWillUnmount()
of the class components, which means it will execute when the component is mounted, when the state of the component changes and when the component is unmounted from the DOM.
Check below example,
useEffect(() => {
setTimeout(() => {
alert("data saved");
}, 1000);
});
Above code/alert is executed when the component is mounted/initial render, when state of the component changes and when component is unmounted from the DOM.
To make the above code run less often we can pass an array of values as the second argument, as the dependencies for that effect. If one of the dependencies change the effect will run again.
Consider we have persons array passed into the props of the functional component and we want the alert to execute only when the persons array change.
useEffect(() => {
setTimeout(() => {
alert("data saved");
}, 1000);
}, [props.persons]);
This will execute the code during initial render and when props.persons
changes.
So to execute the code only during initial render/component mount you can pass an empty array which means no dependencies specified when the effect should execute. Hence run during initial render and when the component is unmounted.
useEffect(() => {
setTimeout(() => {
alert("data saved");
}, 1000);
}, []);
You can modify your useEffect()
hook as below to call it only once to fetch API data,
useEffect(() => {
loadMessages();
}, []);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With