
Ребята из nfl вылечили одну из болей React js, работу с head. Речь пойдет о библиотеке react-helmet. Она работает как на клиенте, так и на сервере.
В предыдущей статье я писал о бойлер-плейте, в котором уже использутся react-helmet, поэтому возьму его:
git clone https://github.com/BoryaMogila/koa_react_redux.git; npm install; npm run-script run-with-build;
Для тех, у кого своя сборка, ставим модуль:
npm install --save react-helmet
Подключаем в своем в компоненте:
import { Component } from 'react' import Helmet from "react-helmet" class SomeComponent extends Component { render(){ return ( <div> <Helmet htmlAttributes={{"lang": "en", "amp": undefined}} // amp takes no value title="My Title" titleTemplate="MySite.com - %s" defaultTitle="My Default Title" base={{"target": "_blank", "href": "http://mysite.com/"}} meta={[ {"name": "description", "content": "Helmet application"}, {"property": "og:type", "content": "article"} ]} link={[ {"rel": "canonical", "href": "http://mysite.com/example"}, {"rel": "apple-touch-icon", "href": "http://mysite.com/img/apple-touch-icon-57x57.png"}, {"rel": "apple-touch-icon", "sizes": "72x72", "href": "http://mysite.com/img/apple-touch-icon-72x72.png"} ]} script={[ {"src": "http://include.com/pathtojs.js", "type": "text/javascript"}, {"type": "application/ld+json", innerHTML: `{ "@context": "http://schema.org" }`} ]} //Ваш код </div> ); }
Helmet можно использовать в компонентах любой степени вложености, при этом свойства, заданные в компоненте ниже уровнем, будут перетирать свойства, заданные в компоненте уровнем выше.
class SomeComponent extends Component { render(){ return ( <div> <Helmet title="My Title" meta={[ {"name": "description", "content": "Helmet application"} ]} link={[ {"rel": "apple-touch-icon", "href": "http://mysite.com/img/apple-touch-icon-57x57.png"}, {"rel": "apple-touch-icon", "sizes": "72x72", "href": "http://mysite.com/img/apple-touch-icon-72x72.png"} ]} base={{"href": "http://mysite.com/"}} /> <AnotherComponent /> </div> ) } } class AnotherComponent extends Component { render(){ return ( <div> <Helmet title="Nested Title" meta={[ {"name": "description", "content": "Nested component"} ]} link={[ {"rel": "apple-touch-icon", "href": "http://mysite.com/img/apple-touch-icon-180x180.png"} ]} base={{"href": "http://mysite.com/blog"}} /> </div> ) } }
В итоге получим:
<head> <title>Nested Title</title> <meta name="description" content="Nested component"> <link rel="apple-touch-icon" href="http://mysite.com/img/apple-touch-icon-180x180.png"> <base href="http://mysite.com/blog"> </head>
Для тайтла есть возможность задать шаблон:
<Helmet defaultTitle="My Site" titleTemplate="My Site - %s" /> <Helmet title="Nested Title" />
Результат:
<head> <title>My Site - Nested Title</title> </head>
Создание тега script:
<Helmet script={[{ "type": "application/ld+json", "innerHTML": `{ "@context": "http://schema.org", "@type": "NewsArticle" }` }]} />
Результат:
<head> <script type="application/ld+json"> { "@context": "http://schema.org", "@type": "NewsArticle" } </script> </head>
Создание тега style:
<Helmet style={[{ "cssText": ` body { background-color: green; } ` }]} />
Результат:
<head> <style> body { background-color: green; } </style> </head>
Для получения данных для head на сервере нужно вызвать метод rewind() после ReactDOM.renderToString или ReactDOM.renderToStaticMarkup.
Возвращенный объект head имеет семь возможных параметров:
- htmlAttributes
- title
- base
- meta
- link
- script
- style
Они имеют два метода toComponent() и toString().
Преобразование данных в строку:
let markup = ReactDOM.renderToString(<Handler />); let head = Helmet.rewind(); const html = ` <!doctype html> <html ${head.htmlAttributes.toString()}> <head> ${head.title.toString()} ${head.meta.toString()} ${head.link.toString()} </head> <body> <div id="content"> ${markup} </div> </body> </html>` //ответ сервера ctx.body = html;
Решение в стиле React:
let markup = ReactDOM.renderToString(<Handler />); let head = Helmet.rewind(); function HTML () { const attrs = head.htmlAttributes.toComponent(); return ( <html {...attrs}> <head> {head.title.toComponent()} {head.meta.toComponent()} {head.link.toComponent()} </head> <body> <div id="content"> // React stuff here </div> </body> </html> ); } //ответ сервера ctx.body = ReactDOM.renderToString(<HTML />);
Готовые рабочие примеры для использования:
P.S. Как всегда рад услышать ваши замечания и дополнения.
