My component has two Rect.useEffect
hook
const Example = ({ user }) => {
React.useEffect(() => {
autorun(() => {
console.log("inside autorun", user.count);
});
});
// Only runs once
React.useEffect(() => {
console.log("Why not me?");
});
return <Observer>{() => <h1>{user.count}</h1>}</Observer>;
};
I update this component using mobx
. It is re-rendered correctly. But "Why not me?"
is printed only once.
As per official docs
By default, effects run after every completed render
This means console.log("Why not me?");
too should run every time prop user
is updated. But it doesn't. The console output is this
What's the reason behind this apparent inconsistency?
My complete code can be viewed here
The useEffect Hook Usages. The callback function we pass to the useEffect hook runs the side effects. React runs it on every render of a component by default.
By default, useEffect runs after every render, but it's also perfect for running some code in response to a state change. You can limit when the effect runs by passing the second argument to useEffect. Think of the second argument as an array of “dependencies” – variables that, if changed, the effect should rerun.
By default, useEffect will run on initial render as well as every future render (update) of your component.
The infinite re-renders problem The reason our component is re-rendering is because our useEffect dependency is constantly changing. But why? We are always passing the same object to our hook! While it is true that we are passing an object with the same key and value, it is not the same object exactly.
In Mobx, just like Observer
component which provides a render function callback, autorun
function also executes independently of the react lifecycle.
This behaviour happens because you have user count as a observable variable.
According to the mobx-react docs
Observer is a React component, which applies observer to an anonymous region in your component. It takes as children a single, argumentless function which should return exactly one React component. The rendering in the function will be tracked and automatically re-rendered when needed.
and mobx docs
When
autorun
is used, the provided function will always be triggered once immediately and then again each time one of its dependencies changes.
You can confirm this behvaior by logging directly inside the functional component and you will observer that the component is only rendered once
EDIT:
To answer your question
If I change
useEffect
to thisReact.useEffect(autorun(() => {console.log("inside autorun", user.count)}));
basically remove anonymous function from
useEffect
and just pass autorun directly, then it is run only once. Why is it so? What's the difference?
The difference is that autorun
returns a disposer function
which when run will dispose of the autorun
and would not longer execute it.
From the docs:
The return value from autorun is a disposer function, which can be used to dispose of the autorun when you no longer need it.
Now what happens is that since useEffect executes the callback provided to it when it runs, the callback executed is the disposer
function returned by autorun which essentially cancels your autorun.
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