Почему useEffect не срабатывает при каждом рендеринге?

У моего компонента есть два крючка 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. Но это не так. Вывод консоли такой

Почему useEffect не срабатывает при каждом рендеринге?

В чем причина этого кажущегося несоответствия?

Мой полный код можно посмотреть здесь

Почему useEffect не срабатывает при каждом рендеринге?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
5
0
3 223
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Похоже, ваш компонент не перерисовывается. 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 autorun is used, the provided function will always be triggered once immediately and then again each time one of its dependencies changes.

Вы можете подтвердить это поведение, войдя непосредственно в функциональный компонент, и вы увидите, что компонент отображается только один раз.

Обновлено:

Чтобы ответить на ваш вопрос

If I change useEffect to this

React.useEffect(autorun(() => {console.info("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?

Разница в том, что 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 напрямую, то она запустится только один раз. Почему это так? Какая разница?

Andrew-Dufresne 01.04.2019 11:46

@ Эндрю-Дюфресн Обновил ответ с объяснением

Shubham Khatri 01.04.2019 12:10

Другие вопросы по теме