Компонент React с утечкой памяти

#javascript #node.js #reactjs #memory-leaks #garbage-collection

#javascript #node.js #reactjs #утечки памяти #сборка мусора

Вопрос:

У меня есть фрагмент устаревшего кода, который отображает компонент react на сервере при каждом запросе, что делает очевидной утечку памяти. Я загнал проблему в угол до этого кода:

   componentWillMount: function () {
    var onLogin = this.props.onLogin || function () {},
        onLogout = this.props.onLogout || function () {};

    this.on('authChange', function () {
      console.log('user authenticated:', this.state.isAuthenticated);
      return this.state.isAuthenticated
              ? onLogin(this.state)
              : onLogout(this.state);
    }.bind(this));
  },
  

Я полагаю, что при каждом запросе this объект сохраняет нового слушателя, но я не понимаю, почему this элемент не помечается как мусор при выполнении рендеринга компонента.

Ответ №1:

Вам необходимо отменить привязку authChange обработчика до того, как компонент будет размонтирован. Вы можете сделать это в componentWillUnmount .

Поскольку вы создаете функцию-обработчик, используя первые переданные реквизиты, вам следует сохранить его в свойстве, чтобы позже можно было отменить привязку:

   componentWillMount: function () {
    var onLogin = this.props.onLogin || function () {},
        onLogout = this.props.onLogout || function () {};

    this.authChange = function () {
      console.log('user authenticated:', this.state.isAuthenticated);
      return this.state.isAuthenticated
              ? onLogin(this.state)
              : onLogout(this.state);
    }.bind(this);

    this.on('authChange', this.authChange);
  },

  componentWillUnmount: function () {
      this.off('authChange', this.authChange);
      this.authChange = null;
  }
  

Обратите внимание, что когда я увидел this.on , я подумал, что вы, возможно, используете jQuery, но неясно, как это могло бы быть в случае. В моем ответе используется this.off для отсоединения прослушивателя событий, но вы должны использовать любой соответствующий метод в вашей среде.

Комментарии:

1. Но разве this компонент не должен быть помечен как мусор в любом случае, когда renderToString() функция завершена?

Ответ №2:

Я бы перенес вашу функцию в componentDidMount и добавил очистку на componentWillUnmount

Важно: componentWillMount вызывается на сервере и клиенте, но componentDidMount вызывается только на клиенте.

Если вы используете eventListeners , setInterval или другие функции, которые необходимо очистить, вставьте их componentDidMount . Сервер не выполняет вызов componentWillUnmount и обычно является причиной утечек памяти.