React Canaryバージョンにおけるtitle要素の新たな挙動
Reactのカナリアバージョンではコンポーネントからtitle
要素を用いることでドキュメントのタイトルを設定可能になります。
最新バージョン
まずは、現在の最新バージョンであるv18.2.0で挙動を確認します。
コンポーネント内でtitle
要素を用いると、用いた場所通りにtitle
要素が描画されます。
<div>
<p>⬇︎⬇︎⬇︎タイトル⬇︎⬇︎⬇︎</p>
<title>タイトル</title>
<p>⬆︎⬆︎⬆︎タイトル⬆︎⬆︎⬆︎</p>
</div>
上記のようなJSXを記述した場合、描画結果も同じようになります。
<div>
<p>⬇︎⬇︎⬇︎タイトル⬇︎⬇︎⬇︎</p>
<title>タイトル</title>
<p>⬆︎⬆︎⬆︎タイトル⬆︎⬆︎⬆︎</p>
</div>
検索エンジンやブラウザの挙動によってはbody
要素内にtitle
がある場合はそれがドキュメントのタイトルと読み取ってくれないことが多いのでこのような結果は避けたいです。そもそも、title
要素はHTMLの標準ではhead
要素内に配置するように規定されているので、body
要素内に配置されるのは相応しくありません。
さらに、描画先のHTMLのhead
要素にすでにtitle
が設定済みな場合はドキュメントのタイトルを更新できないのでこの方法でドキュメントのタイトルを設定することは難しいです(そしてそのケースに該当することは多いと思います)。
実際にコンポーネント内でtitle
を設定するデモは以下の通りです。
カナリアバージョン
次にReactのカナリアバージョンにおける挙動を確認しましょう。
<div>
<p>⬇︎⬇︎⬇︎タイトル⬇︎⬇︎⬇︎</p>
<title>タイトル</title>
<p>⬆︎⬆︎⬆︎タイトル⬆︎⬆︎⬆︎</p>
</div>
先ほどと同じように上記のようなJSXを記述した場合、描画結果は以下のようになります。
<div>
<p>⬇︎⬇︎⬇︎タイトル⬇︎⬇︎⬇︎</p>e>
<p>⬆︎⬆︎⬆︎タイトル⬆︎⬆︎⬆︎</p>
</div>
該当するコンポーネントからtitle
要素の部分が消えています。消えたtitle
要素はhead
要素内に追加されます。既にtitle
要素が設定されていた場合は先頭に追加されます。
先頭に追加されるため、ドキュメントのタイトルが設定したものに変更されます。
先程と同じようなデモですが、今回はタイトルが変更されていることが確認できると思います。
注意点
複数宣言する
title
要素は他の要素と同じように複数のコンポーネントで複数の箇所で宣言可能です。それらが描画されると、head
要素内にtitle
要素が次々追加さます。
単一のコンポーネントで複数宣言する場合のデモは以下のとおりです。
レンダリングされる順番通りにhead
要素内title
要素が追加されて行くように見えます。
単一のコンポーネントでしたのでどのようにtitle
要素が追加されるかわかりやすかったですが、複数のコンポーネントではtitle
要素がどのように追加されるか想像するのが難しくドキュメントのタイトルをうまく設定できません。
さらに今後の改修によってtitle
要素がどのように追加されるかは変化する可能性もありますし、title
要素が多いことで検索エンジンやブラウザ等の解釈に悪影響があるかもしれません。レンダリング毎に宣言するtitle
要素はできるだけ1つとなるようにしてください。
このような背景があるので、Reactでtitle
要素を設定するようにする場合は描画先のHTMLのhead
要素にtitle
要素を配置しない方が良いと思います。
コンポーネントで宣言したtitle
要素はライフサイクルに合わせてhead
要素から取り除かれます。同じライフサイクルでレンダリングされないコンポーネントからtitle
要素を宣言するのは問題ありません。
children
title
要素のchildren
は単一の文字列である必要があります。
下記のデモを見てください(動作を確認するためにtitle
要素を複数宣言しています)。
title
要素をそれぞれhello {world}
と{'hello ' + world}
で宣言しました。head
要素内を見てみると、前者は<title></title>
として設定され、後者は<title>hello world</title>
と設定されています。
console
を見てください。それぞれがどのようにレンダリングされているかを確認できます。多くは変わりませんが、props
のchildren
が配列になっているものと文字列になっているものに分かれていると思います。
// 前者のconsole logを抜粋
{
$$typeof: Symbol(react.element)
key: null,
props: {
children: ['hello ', 'world'],
},
ref: null,
type: 'title',
}
// 後者のconsole logを抜粋
{
$$typeof: Symbol(react.element)
key: null,
props: {
children: 'hello world',
},
ref: null,
type: 'title',
}
title
要素を利用するときはchildren
が文字列となるようにする必要があります。
自明な仕様ではありませんが、利用する際は注意してください。
例外
以下のパターンでtitle
が利用された場合は挙動が最新のバージョンと同じになります。
-
svg
要素内のtitle
要素 -
title
要素がprops
にitemProp
を持つ(itempropについては仕様書を確認してください)
どちらもドキュメントのタイトルに設定するとは異なる意味を持つのでこのような仕様になっています。むしろ通常の利用が例外的にhead
要素内に追加されると考えた方が良いと思います。
Discussion