#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
, то это гарантированно:
- Запуск только на стороне клиента
- Убедитесь, что
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
, он будет работать.