У моего компонента есть два крючка Rect.useEffect
const Example = ({ user }) => {
React.useEffect(() => {
autorun(() => {
console.info("inside autorun", user.count);
});
});
// Only runs once
React.useEffect(() => {
console.info("Why not me?");
});
return <Observer>{() => <h1>{user.count}</h1>}</Observer>;
};
Я обновляю этот компонент с помощью mobx. Он перерисовывается правильно. Но "Why not me?" печатается только один раз.
Согласно официальные документы
By default, effects run after every completed render
Это означает, что console.info("Why not me?"); тоже должен запускаться каждый раз, когда обновляется свойство user. Но это не так. Вывод консоли такой

В чем причина этого кажущегося несоответствия?
Мой полный код можно посмотреть здесь





Похоже, ваш компонент не перерисовывается. autorun получает обратный вызов и может вызывать его независимо от рендера.
Example компонент перерисовывается только тогда, когда перерисовывается его родитель или когда его свойства меняются.
Используйте этот код, чтобы наблюдать, что происходит на самом деле:
const Example = ({ user }) => {
console.info('render');
React.useEffect(() => {
console.info('useEffect autorun');
autorun(() => {
console.info("inside autorun", user.count);
});
});
// Only runs once
React.useEffect(() => {
console.info("Why not me?");
});
return <Observer>{() => <h1>{user.count}</h1>}</Observer>;
};
В Mobx, как и компонент Observer, который обеспечивает обратный вызов функции рендеринга, функция autorun также выполняется независимо от жизненного цикла реакции.
Такое поведение происходит из-за того, что у вас есть количество пользователей как наблюдаемая переменная.
Согласно документам mobx-react
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.
и мобкс документы
When
autorunis used, the provided function will always be triggered once immediately and then again each time one of its dependencies changes.
Вы можете подтвердить это поведение, войдя непосредственно в функциональный компонент, и вы увидите, что компонент отображается только один раз.
Обновлено:
Чтобы ответить на ваш вопрос
If I change
useEffectto thisReact.useEffect(autorun(() => {console.info("inside autorun", user.count)}));basically remove anonymous function from
useEffectand just pass autorun directly, then it is run only once. Why is it so? What's the difference?
Разница в том, что autorun возвращает disposer function, который при запуске избавится от autorun и больше не будет его выполнять.
Из документов:
The return value from autorun is a disposer function, which can be used to dispose of the autorun when you no longer need it.
Теперь происходит то, что, поскольку useEffect выполняет обратный вызов, предоставленный ему при запуске, выполняемый обратный вызов — это функция disposer, возвращаемая автозапуском, которая по существу отменяет ваш автозапуск.
@ Эндрю-Дюфресн Обновил ответ с объяснением
Это отличное объяснение. Если я заменю
useEffectна этоReact.useEffect(autorun(() => {console.info("inside autorun", user.count)}));, в основном удалю анонимную функцию изuseEffectи просто передамautorunнапрямую, то она запустится только один раз. Почему это так? Какая разница?