React.js Сервер рендеринга и обработчики событий
Я учусь использовать response.js и у меня есть некоторые проблемы, чтобы использовать обработчики событий. Последний вопрос: можно ли использовать рендеринг на стороне сервера и автоматически отправлять обработчики событий клиенту?
Вот мой пример: у меня есть index.jsx, который я отображаю на стороне сервера и отправляю клиенту
var React = require("react");
var DefaultLayout = require("./layout/default");
var LikeButton = React.createClass({
getInitialState: function() {
return {liked: false};
},
handleClick: function(event) {
this.setState({liked: !this.state.liked});
},
render: function() {
var text = this.state.liked ? 'like' : 'haven\'t liked';
return (
<p onClick={this.handleClick}>
You {text} this. Click to toggle.
</p>
);
}
});
var IndexComponent = React.createClass({
render: function(){
return (
<DefaultLayout title={this.props.name}>
<div>
<h1>React Test</h1>
</div>
<div id="testButton">
<LikeButton/>
</div>
<script type="text/babel" src="/js/react.js"></script>
</DefaultLayout>
)
}
});
Но кнопка "Мне нравится" не имеет никакого взаимодействия. Чтобы заставить это делать что-то по щелчку, я должен добавить этот код на стороне клиента.
var LikeButton = React.createClass({
getInitialState: function() {
return {liked: false};
},
handleClick: function(event) {
this.setState({liked: !this.state.liked});
},
render: function() {
var text = this.state.liked ? 'like' : 'haven\'t liked';
return (
<p onClick={this.handleClick}>
You {text} this. Click to toggle.
</p>
);
}
});
ReactDOM.render(
<LikeButton />,
document.getElementById('testButton')
);
Я только начал с response.js и, может быть, мне здесь не хватает какой-то важной концепции. Но почему response.js не просто создает код (который я теперь должен добавить вручную к клиенту) при рендеринге серверной части страницы? Таким образом, у меня есть избыточный код, и я чувствую, что это будет беспорядок в больших приложениях. По крайней мере, response.js достаточно умен, чтобы не рисовать две кнопки LikeButton, а "привязывать" одну созданную сторону сервера к клиентскому компоненту.
3 ответа
Для интерактивного приложения React на стороне клиента необходимо также отобразить клиентское приложение. Обычно этот код идентичен коду, который вы запускаете на сервере, поэтому избыточного кода нет. Это просто тот же код. Вы можете спросить себя, является ли рендеринг как на клиенте, так и на сервере, излишним, но с точки зрения производительности и SEO это имеет смысл.
ReactDOMServer.renderToString(<MyApp foo={bar} />)
в основном просто визуализирует строку с разметкой. Там нет ни JavaScript, ни какой-либо магии. Просто старый HTML. Однако отображаемая разметка имеет множество атрибутов React ID, которые впоследствии используются на клиенте для генерации начального Virtual DOM и присоединения событий.
Когда вы снова визуализируете свое приложение на клиенте, в том же элементе DOM, в котором на сервере была введена разметка на стороне сервера, React не нужно перерисовывать все приложение. Он просто создает новое дерево Virtual DOM, сравнивает его с исходным деревом Virtual DOM и выполняет необходимые операции DOM, если таковые имеются. Именно эта концепция виртуального DOM делает React такой быстрой. В этом же процессе все прослушиватели событий, которые вы определили в своем приложении, будут присоединены к уже обработанной разметке.
Все это происходит очень быстро. И у вас есть то преимущество, что страница, отображаемая на стороне сервера (которую можно кэшировать на сервере, используя Varnish или что-то подобное), будет сканироваться поисковыми системами, пользователям не нужно ждать, чтобы увидеть начальный рендер, и страницу. в основном работает для пользователей, которые отключили JavaScript.
Такое поведение объясняется тем, что именно рендеринг на стороне сервера. Во-первых, вам придется запускать один и тот же код как на стороне клиента, так и на стороне сервера. Это то, что называется изоморфным приложением. Тот, который работает как на сервере, так и на клиенте.
Итак, делать ReactDOM.renderToString(<Component>)
только HTML отображается как строка. Метод рендеринга вашего компонента оценивается и генерируется HTML-код, необходимый для первоначального рендеринга.
Когда тот же код выполняется на клиенте, реагирует на просматриваемый HTML-код и подключает JS в необходимых местах. React умный, он не перерисовывает все заново на стороне клиента. Просто оценивает код и определяет, куда все прикрепить код на основе react-id
каждый элемент DOM задан. (Вы будете реагировать на идентификатор, если вы проверяете элемент любого реагирующего приложения)
Теперь можно спросить, какая выгода от того, что вы делаете одно и то же дважды?
и ответ perceived loading time
пользователем. А также немного минимального просмотра для пользователей, которые отключили JS.
Клиент подал заявку
Так работает приложение, созданное исключительно клиентом. (клиент также обработал приложение React)
Пользователь будет видеть контент только после всех скелетов HTML, JS-пакетов (которые часто бывают довольно большими), а данные извлекаются и оцениваются. Это означает, что пользователю часто придется некоторое время смотреть на вертушку или загрузочный экран, пока все не загрузится.
Изоморфное приложение (работает как на клиенте, так и на сервере)
Как работает изоморфное приложение,
В этом случае сервер генерирует полный HTML-код, оценивая ваш компонент. И пользователь увидит контент сразу же, как только HTML будет загружен. Хотя приложение будет полностью функционировать только после загрузки и оценки пакетов JS. Так что JS должен бежать с обеих сторон
Таким образом, пользователь видит контент намного быстрее, чем раньше. Отсюда и огромное уменьшение воспринимаемого времени загрузки.
В дополнение к приведенным выше ответам на стороне CSR вам также необходимо заменитьReactDOM.render
кReactDOM.hydrate
Также вы можете использовать один и тот же файл LikeButton в SSR и CSR, единственное, что происходит, это событие onClick на стороне SSR не будет реагировать ни на что.