Реакция на стороне сервера
- Преимущества рендеринга на стороне сервера
- Начиная
- Добавление рендеринга на стороне сервера
- Выборка данных перед рендерингом
- Идти дальше
React наиболее известен как клиентский JavaScript-фреймворк, но знаете ли вы, что можете (и, возможно, должны!) Рендерить React на стороне сервера ?
Предположим, вы создали новое клиентское приложение React, содержащее список событий. Приложение подключено к API, созданному с помощью вашего любимого серверного инструмента. Пару недель спустя клиент сообщает вам, что его страницы не отображаются в Google и выглядят не очень хорошо при публикации в Facebook. Кажется разрешимым, верно?
Вы решаете, что для решения этой проблемы вам нужно будет визуализировать страницы React с сервера при начальной загрузке, чтобы сканеры из поисковых систем и сайтов социальных сетей могли читать вашу разметку. Существуют доказательства того, что Google иногда выполняет javascript и может индексировать сгенерированный контент, но не всегда. Поэтому рендеринг на стороне сервера всегда рекомендуется, если вы хотите обеспечить хорошее SEO и совместимость с другими сервисами, такими как Facebook, Twitter.
В этом руководстве мы подробно рассмотрим пример рендеринга на стороне сервера. включая обход общего барьера для приложений React, которые общаются с API.
Преимущества рендеринга на стороне сервера
SEO может быть тем разговором, который заставляет вашу команду говорить о рендеринге на стороне сервера, но это не единственное потенциальное преимущество.
Вот большой пример: рендеринг на стороне сервера отображает страницы быстрее . При рендеринге на стороне сервера ответ вашего сервера на браузер - это HTML-код вашей страницы, который готов к визуализации, поэтому браузер может начать рендеринг, не дожидаясь загрузки и выполнения всего JavaScript. Там нет «белой страницы», пока браузер загружает и выполняет JavaScript и другие ресурсы, необходимые для отображения страницы, что может происходить на полностью отрисованном клиентом сайте React.
Начиная
Давайте рассмотрим, как добавить рендеринг на стороне сервера в базовое клиентское приложение React с Babel и Webpack. Наше приложение будет иметь дополнительную сложность получения данных от стороннего API. Мы предоставили стартовый код на GitHub, где вы можете увидеть полный пример.
Начальный код имеет только один компонент React, `hello.js`, который выполняет асинхронный запрос к ButterCMS API и отображает возвращенный список сообщений в блоге в формате JSON. ButterCMS - это блоговый движок на основе API, который бесплатен для личного использования, поэтому он отлично подходит для тестирования реальных случаев использования. Начальный код поставляется с токеном API, но при желании вы можете получить свой собственный токен API с помощью вход в ButterCMS с вашей учетной записью GitHub ,
импорт React из 'реакции'; импорт сливочного масла из 'buttercms' const butter = Butter ('b60a008584313ed21803780bc9208557b3b49fbb'); var Hello = React.createClass ({getInitialState: function () {return {loaded: false};}, componentWillMount: function () {butter.post.list (). then ((resp) => {this.setState ({ загружен: true, соответственно: resp.data})});}, render: function () {if (this.state.loaded) {return (<div> {this.state.resp.data.map ((post)) => {return (<div key = {post.slug}> {post.title} </ div>)})} </ div>);} else {return <div> Загрузка ... </ div>; }}}); экспорт по умолчанию Hello;
Вот что еще включено в стартовый код:
- `package.json` - для зависимостей
- Конфигурация Webpack и Babel
- `index.html` - HTML-код для приложения
- `index.js` - загружает React и отображает компонент Hello
Чтобы запустить приложение, сначала клонируйте репозиторий:
мерзкий клон ... кд ..
Установите зависимости:
установка npm
Затем запустите сервер разработки:
Npm Run Start
Перейдите по адресу http: // localhost: 3000, чтобы просмотреть приложение:
Если вы просмотрите исходный код отображаемой страницы, вы увидите, что разметка, отправленная в браузер, является просто ссылкой на файл JavaScript. Это означает, что содержание этой страницы не гарантируется для поисковых систем и социальных сетей:
Добавление рендеринга на стороне сервера
Далее мы реализуем рендеринг на стороне сервера, чтобы полностью сгенерированный HTML-код отправлялся в браузер. Если вы хотите просмотреть все изменения сразу, посмотреть различия в Git ЧАС UB ,
Для начала мы установим Express, среду приложения на стороне сервера Node.js.
npm установить экспресс --save
Мы хотим создать сервер, который отображает наш компонент React:
импорт экспресс из 'экспресс'; импортировать фс из 'фс'; импортировать путь из 'path'; импорт React из 'реакции'; импортировать ReactDOMServer из «act-dom / server »; импортировать Hello из './Hello.js'; function handleRender (req, res) {// Отрисовывает наш компонент Hello в строку HTML const html = ReactDOMServer.renderToString (<Hello />); // Загружаем содержимое index.html fs.readFile ('./ index.html', 'utf8', function (err, data) {if (err) throw err; // Вставляем визуализированный код React HTML в наш основной элемент div const document = data.replace (/ <div id = "app"> <\ / div> /, `<div id =" app "> $ {html} </ div>`); // отправляет ответ обратно клиентский res.send (документ);}); } const app = express (); // Обслуживание встроенных файлов со статическими файлами middleware app.use ('/ build', express.static (path.join (__dirname, 'build')))); // Обслуживаем запросы с помощью нашего handleRender function app.get ('*', handleRender); // Запустить сервер app.listen (3000);
Давайте разберемся, что происходит ...
Функция handleRender обрабатывает все запросы. Класс ReactDOMServer Импорт в верхней части файла обеспечивает метод renderToString (), который отображает элемент React в его исходный HTML.
ReactDOMServer.renderToString (<Hello />);
Это возвращает HTML для компонента Hello, который мы внедряем в HTML файла index.html, чтобы сгенерировать полный HTML-код для страницы на сервере.
const document = data.replace (/ <div id = "app"> <\ / div> /, `<div id =" app "> $ {html} </ div>`);
Чтобы запустить сервер, обновите скрипт запуска в `package.json` и затем запустите npm run start:
"scripts": {"start": "webpack && babel-node server.js"},
Перейдите по адресу http: // localhost: 3000, чтобы просмотреть приложение. Вуаля! Ваша страница теперь отображается с сервера. Но есть проблема. Если вы просматриваете страницу источника в браузере. Вы заметите, что сообщения блога по-прежнему не включены в ответ. В чем дело? Если мы откроем вкладку сети в Chrome, то увидим, что запрос API происходит на клиенте.
Хотя мы рендерим компонент React на сервере, запрос API выполняется в componentWillMount асинхронно, а компонент обрабатывается до завершения запроса. Поэтому, хотя мы выполняем рендеринг на сервере, мы делаем это только частично. Оказывается, есть выпуск репо React более 100 комментариев обсуждают проблему и различные обходные пути.
Выборка данных перед рендерингом
Чтобы это исправить, мы должны убедиться, что запрос API завершен до того, как будет обработан компонент Hello. Это означает выполнение запроса API вне цикла рендеринга компонента React и выборку данных до того, как мы выполним рендеринг компонента. Мы проведем вас через это шаг за шагом, но вы можете просмотреть полный diff на Git ЧАС UB ,
Чтобы переместить выборку данных перед рендерингом, мы установим реагируют-передачи :
npm установить реагировать-передавать --save
React Transmit предоставляет нам элегантные компоненты-оболочки (часто называемые «компонентами более высокого порядка») для извлечения данных, которые работают на клиенте и сервере.
Вот как выглядит наш компонент с внедрением React Transmit:
импорт React из 'реакции'; импорт Масло из «buttercms» импорт «Передача» из «реакции-передачи»; const butter = Butter ('b60a008584313ed21803780bc9208557b3b49fbb'); var Hello = React.createClass ({render: function () {if (this.props.posts) {return (<div> {this.props.posts.data.map ((post) => {return (<ключ div) = {post.slug}> {post.title} </ div>)})} </ div>);} else {return <div> Загрузка ... </ div>;}}}); export default Transmit.createContainer (Hello, {// Они должны быть установлены, в противном случае будет невозможно отобразить initialVariables: {}, // Каждый фрагмент будет преобразован в фрагменты prop: {posts () {return butter.post.list () .then ((resp) => resp.data);}}});
Мы завернули наш компонент в компонент более высокого порядка, который извлекает данные с использованием Transmit.createContainer. Мы удалили методы жизненного цикла из компонента React, поскольку нет необходимости извлекать данные дважды. И мы изменили метод рендеринга, чтобы использовать ссылки на реквизиты вместо состояния, поскольку React Transmit передает данные компоненту как реквизиты.
Чтобы убедиться, что сервер извлекает данные перед рендерингом, мы импортируем Transmit и используем Transmit.renderToString вместо метода ReactDOM.renderToString.
импорт экспресс из 'экспресс'; импортировать фс из 'фс'; импортировать путь из 'path'; импорт React из 'реакции'; импортировать ReactDOMServer из «act-dom / server »; импортировать Hello из './Hello.js'; импорт Передача из «реакции-передачи»; function handleRender (req, res) {Transmit.renderToString (Hello) .then (({actString, reactData}) => {fs.readFile ('./ index.html', 'utf8', function (err, data) { if (err) throw err; const document = data.replace (/ <div id = "app"> <\ / div> /, `<div id =" app "> $ {ReactionString} </ div>`); const output = Transmit.injectIntoMarkup (document, ReactionData, ['/build/client.js']); res.send (document);});}); } const app = express (); // Обслуживание встроенных файлов со статическими файлами middleware app.use ('/ build', express.static (path.join (__dirname, 'build')))); // Обслуживаем запросы с помощью нашего handleRender function app.get ('*', handleRender); // Запустить сервер app.listen (3000);
Перезапустите сервер, перейдите по адресу http: // localhost: 3000. Посмотрите исходный код страницы, и вы увидите, что страница полностью отображается на сервере!
Идти дальше
Мы сделали это! Использование React на сервере может быть сложным, особенно при извлечении данных из API. К счастью, сообщество React процветает и создает множество полезных инструментов. Если вы заинтересованы в каркасах для создания больших приложений React, которые отображаются на клиенте и сервере, посмотрите электрод Walmart Labs или Next.js , Или, если вы хотите сделать React в Ruby, посмотрите AirBnB's Hypernova ,
Кажется разрешимым, верно?В чем дело?