Утечка памяти для рендеринга на стороне сервера React

#reactjs #server-side-rendering #react-server

#reactjs #отрисовка на стороне сервера #react-сервер

Вопрос:

Приведенный ниже код по ссылке react гласит, что:

К сожалению, это может привести к утечкам памяти для рендеринга на сервере (где componentWillUnmount никогда не будет вызван)

 // Before
class ExampleComponent extends React.Component {
  componentWillMount() {
    this.setState({
      subscribedValue: this.props.dataSource.value,
    });

    // This is not safe; it can leak!
    this.props.dataSource.subscribe(
      this.handleSubscriptionChange
    );
  }

  componentWillUnmount() {
    this.props.dataSource.unsubscribe(
      this.handleSubscriptionChange
    );
  }

  handleSubscriptionChange = dataSource => {
    this.setState({
      subscribedValue: dataSource.value,
    });
  };
}
  

Я не могу понять, как это может быть утечкой памяти на стороне сервера. Например, допустим, у нас есть этот код, который рендерится на стороне сервера, и ExampleComponent содержит утечку памяти.

 import React from 'react';
import ReactDomServer from 'react-dom/server';
import App from './components/index'

const serverRender =  () =>{
    return ReactDomServer.renderToString(<ExampleComponent />);
};

export default serverRender;
  

Когда это возвращается клиенту, обработанные компоненты никуда не прикреплены и готовы к сбору в ГБ. Итак, почему происходит утечка памяти?

Ответ №1:

Ответ указан в документах:

Люди часто предполагают, что componentWillMount и componentWillUnmount всегда сопряжены, но это не гарантировано

Очевидная причина заключается в том, что componentWillMount запускается, когда компонент собирается смонтировать, поэтому, если монтирование прервано, компонент никогда не будет смонтирован и, следовательно, никогда не будет размонтирован. Однако в предыдущем разделе документации также указана причина, по которой показан код:

 componentWillMount() {

    this.setState({
      subscribedValue: this.props.dataSource.value,
    });

    // This is not safe; it can leak!
    this.props.dataSource.subscribe(
      this.handleSubscriptionChange
    );

} 
  

и говорит

Приведенный выше код проблематичен как для рендеринга на сервере (где внешние данные не будут использоваться), так и для предстоящего режима асинхронного рендеринга (где запрос может быть инициирован несколько раз).

Исходя из этого, можно предположить, что componentWillMount выполняется во время SSR, а также выполняется при загрузке на стороне клиента, что означает, что выполняется дополнительный ненужный запрос, вызывающий потенциальную утечку памяти на сервере.

Однако, если вы используете componentDidMount , то это гарантированно:

  1. Запуск только на стороне клиента
  2. Убедитесь, что componentWillUnmount это всегда будет выполняться впоследствии

Ответ №2:

this.props.dataSource является чем-то внешним и может работать дольше, чем вызывающий компонент subscribe . на handleSubscriptionChange будет ссылаться this.props.dataSource . Также на сам компонент может ссылаться this inside handleSubscriptionChange . Таким образом, ГБ не будет очищаться ExampleComponent вообще.

Поскольку componentWillMount не рекомендуется, вам, вероятно, не следует беспокоиться об этих деталях и просто использовать componentDidMaount .

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

1. This.props.DataSource будет жить дольше, пока сервер будет продолжать работать, верно?

2. Из примера неясно, и это может быть глобальная переменная на сервере. Это зависит от кода сервера и props передается ExampleComponent .

3. Рекомендуется выполнять все вызовы на стороне сервера в componentDidMount . Да, пока вызов не вернется с сервера this.props.dataSource , он будет работать.