Універсальний (изоморфный) «шолом» для React js або Як зручно працювати з head на React js

image
Хлопці з nfl вилікували одну з болю React js, роботу з head. Мова піде про бібліотеку react-helmet. Вона працює як на клієнті, так і на сервері.

попередній статті я писав про бойлер-плейте, в якому вже використовується react-helmet, тому візьму його:

git clone https://github.com/BoryaMogila/koa_react_redux.git;
npm install;
npm run-run script-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. Як завжди радий почути ваші зауваження та доповнення.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.