以下の内容はhttps://let.blog.jp/tag/Routerより取得しました。


ページ内部からヘッダーを更新したい
メインのレイアウトがこんな構造のとき

const Main = () => {
return (
<div>
<Header/>
<Outlet/>
<Footer/>
</div>
)
}

Outlet のコンポーネントがその時点のページを表示します
このページ内の処理で Header や Footer に表示するものを設定したいです
ページタイトルとかそういうの

やろうとすると Main で Context を提供し setHeader みたいな関数にアクセスできるようにして 各ページがマウント時に呼び出します

const Page1 = () => {
const setHeader = useSetHeader()

useEffect(() => {
setHeader({
title: "Page1",
})
}, [])

return (<div>...</div>)
}

あまり気持ちの良い方法ではないです

以前は Outlet のような使い方をする Router を使っていなくて Outlet のところに Router を配置する感じでした
それだと Header などレイアウトを外に配置するメリットもあまりなかったので Page が Main コンポーネントを使うという構造でした

const Page1 = () => {
const header = {
title: "Page1",
}
return (
<Main header={header}>
<div>...</div>
</Main>
)
}

こっちのほうが自然な感じです
とはいえ全部のページで Main を使う必要がありますし Outlet のような機能を持つ Router を使う場合だと Router でマッチしたコンポーネントは外側のコンポーネントの一部として表示する形になります
ページのコンポーネントがレイアウトを選択するのではなく ルーター側でレイアウト内にページを配置するようにしてるので こういう作りにならないです
いい方法はないものなんでしょうか
client router とコンポーネント
ルーターをコンポーネントで作るとき こんな構造になってるのが多いと思う

<app-router>
<app-route route="/">
<app-route route="/foo">
<app-route route="/bar">

ルート定義それぞれがコンポーネントになってて DOM に存在する
1 つ目のルートがアクティブなら

<app-router>
<app-route route="/">
<page-header>
<page-content>
<page-footer>
<app-route route="/foo">
<app-route route="/bar">

3 つ目のルートがアクティブなら

<app-router>
<app-route route="/">
<app-route route="/foo">
<app-route route="/bar">
<page-header>
<page-content>
<page-footer>

アクティブなルート定義コンポーネントの子要素としてページの DOM が作られる
これだと グローバルなヘッダーなど共通なパーツもページ(ルート)ごとに別になる
同じパーツなら見た目上は変わらないけど 再作成してるし無駄も多い
ヘッダーに検索用 input とかあったら再作成でリセットされるし

ShadowDOM を使って共通の場所に作るか app-route を DOM として作らないほうがいいかも

<app-router>
<app-route>
<app-route>
<app-route>
#shadow
<page-header>
<page-content>
<page-footer>
<app-router>
<page-header>
<page-content>
<page-footer>

page-header や page-footer が同じ要素なら使いまわして再作成しないようにする

app-route を作らないなら app-router のプロパティやメソッド呼び出しで DOM ではわからない形でルートを定義する

app_router.routes = [
"/": {},
"/foo": {},
"/bar": {}
]



基本的にはルート定義コンポーネントが直接ページ内の要素を管理しないので ルート定義コンポーネントではルートに対応するページコンポーネントの要素を作って そのコンポーネントがページ要素を管理する構造になるはず

<app-router>
<app-route route="/">
<page-top>
#shadow
<page-header>
<page-content>
<page-footer>
<app-route route="/foo">
<app-route route="/bar">

こうなるとアクティブなときに app-route の子要素に配置しないようにしても

<app-router>
<app-route route="/">
<app-route route="/foo">
<app-route route="/bar">
#shadow
<page-top>

とか

<app-router>
<app-route route="/">
<app-route route="/foo">
<app-route route="/bar">
#shadow
<page-foo>

になって結局ヘッダーなどの要素は共有できてない
ページのコンポーネントじゃなくて共通の部分とページごとの可変部分の親子コンポーネントにすれば良さそう

<app-router>
<default-layout>
<list-content>
<app-router>
<default-layout>
<detail-content>
<app-router>
<special-layout>
<account-content>

*-layout の ShadowDOM 内に *-content を slot で配置

<app-router>
<default-layout>
<list-content>
#shadow
<page-header>
<slot>
<list-content>
<page-footer>

同じ default-layout を使うルート間の移動なら default-layout 要素はそのままなので page-header/page-footer はそのまま維持される

だけど list-content のところで user-list-content と article-list-content があった場合
どっちもリスト系なのでリスト系共通の要素があるけど コンポーネントが分かれるのでここは DOM が異なってしまう
page-header みたいに 同じなら DOM を使いまわしたいなら list-content のところも共通と個別のところを分けて親子構造にする必要が出てくる

<app-router>
<default-layout>
<list-common>
<list-user-content>
#shadow
<page-header>
<slot>
<list-common>
<list-user-content>
#shadow
<list-header>
<slot>
<list-user-content>
<page-footer>

これも大変で面倒だし 実際の DOM にコンポーネントが挟まらない React とか lit-html とかのほうが良いのかも
それ以前に 別に重いとか見た目崩れるとかないなら 無理に DOM の使い回しとかせずページのルートコンポーネントから置き換わっても別に困らないとも思う



以上の内容はhttps://let.blog.jp/tag/Routerより取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14