Skip to main content
Version: 5.3

Layouts

<header> の重複を解決する一つの方法は、 <Header> コンポーネントを作成して、それを HomePageAboutPage の両方で読み込むことです。それは有効ですが、もっと良い方法はないでしょうか?理想を言えば <header> への唯一の参照はコードのどこからでも行えるべきです。

この2つのページを見たとき、彼らが本当に気にしていることは何でしょうか?表示したいコンテンツがあるのです。その前( <header> など)や後( <footer> など)を気にする必要は全くないはずです。そこでレイアウトの出番です:レイアウトはページをコンポーネントでラップし、その子としてページをレンダリングします。レイアウトは、ページ自体の外側にある任意のコンテンツを含むことができます。概念的には、最終的にレンダリングされるドキュメントは次のような構造になっています:

Layouts structure diagram

<header> を保持するためのレイアウトを作りましょう:

yarn redwood g layout blog
tip

ここからは generate の代わりに、より短いエイリアスである g を使います。

web/src/layouts/BlogLayout/BlogLayout.tsx と、関連するテストファイルやストーリーファイルが作成されました。これを "blog" レイアウトと呼んでいるのは、将来的に他のレイアウト("admin" レイアウトとか?)を用意するかもしれないからです。

HomePageAboutPage の両方から <header> を切り取って、代わりにレイアウトに貼り付けます。重複している <main> タグも取り除いてしまいましょう:

web/src/layouts/BlogLayout/BlogLayout.js
import { Link, routes } from '@redwoodjs/router'

const BlogLayout = ({ children }) => {
return (
<>
<header>
<h1>Redwood Blog</h1>
<nav>
<ul>
<li>
<Link to={routes.about()}>About</Link>
</li>
</ul>
</nav>
</header>
<main>{children}</main>
</>
)
}

export default BlogLayout
web/src/pages/AboutPage/AboutPage.js
import { Link, routes } from '@redwoodjs/router'
import { MetaTags } from '@redwoodjs/web'

const AboutPage = () => {
return (
<>
<MetaTags title="About" description="About page" />

<p>
This site was created to demonstrate my mastery of Redwood: Look on my
works, ye mighty, and despair!
</p>
<Link to={routes.home()}>Return home</Link>
</>
)
}

export default AboutPage
web/src/pages/HomePage/HomePage.js
import { MetaTags } from '@redwoodjs/web'

const HomePage = () => {
return (
<>
<MetaTags title="Home" description="Home page" />
Home
</>
)
}

export default HomePage

BlogLayout.tsx では、children がマジックが起こる場所です。レイアウトに与えられたすべてのページコンテンツは、ここでレンダリングされます。これで、ページは関心のあるコンテンツに集中できるようになります(レイアウトが肩代わりしてくれるので HomePage から Linkroutes のインポートを削除することができます)。

レイアウトを実際にレンダリングするには、Routesファイルを変更しなければなりません。 <Set> を使って HomePageAboutPageBlogLayout でラップします。ページとは異なり、レイアウトでは実際に import ステートメントが必要です:

web/src/Routes.js
import { Router, Route, Set } from '@redwoodjs/router'
import BlogLayout from 'src/layouts/BlogLayout'

const Routes = () => {
return (
<Router>
<Set wrap={BlogLayout}>
<Route path="/about" page={AboutPage} name="about" />
<Route path="/" page={HomePage} name="home" />
</Set>
<Route notfound page={NotFoundPage} />
</Router>
)
}

export default Routes
The src alias

import文では src/layouts/BlogLayout を使用しており、 ../src/layouts/BlogLayout./src/layouts/BlogLayout ではないことに注意してください。 src だけで使えるのは、Redwood が提供する便利機能です: src は現在のワークスペースにある src パスのエイリアスです。つまり web で作業している場合は、 srcweb/src を指し、 api では api/src を指します。

ブラウザに戻ると(手動でリロードする必要があるかもしれません)、...何も変わっていないはずです。しかし、これは良いことです。レイアウトが機能しているということです!

Why are things named the way they are?

Redwoodのファイル名の中に重複があることにお気づきかもしれません。ページは /pages というディレクトリにあり、その名前には Page が含まれています。レイアウトも同じです。どうしたことでしょう?

エディタで何十ものファイルを開いていると、すぐ迷子になります。似たような、あるいは(たまたま違うディレクトリにある)同じ名前のファイルがいくつかある場合は特に。index.ts という名前のファイルが何十個もあって、開いているタブの中から探すのを想像してみてください!ファイル名の中の重複は、開いている特定のファイルを探すときの生産性向上に寄与することがわかりました。

React Developer Tools プラグインを使用している場合、コンポーネントスタックをブラウズする際に曖昧さをなくすのにも役立ちます:

Back Home Again

さらに <Links> を:タイトルとロゴはホームに戻るようリンクし、ホームへのナビリンクも追加します:

web/src/layouts/BlogLayout/BlogLayout.js
import { Link, routes } from '@redwoodjs/router'

const BlogLayout = ({ children }) => {
return (
<>
<header>
<h1>
<Link to={routes.home()}>Redwood Blog</Link>
</h1>
<nav>
<ul>
<li>
<Link to={routes.home()}>Home</Link>
</li>
<li>
<Link to={routes.about()}>About</Link>
</li>
</ul>
</nav>
</header>
<main>{children}</main>
</>
)
}

export default BlogLayout

そうしたら、Aboutページにあった余計な "Return to Home" リンク(と、Linkとroutesのimport)を削除できます:

web/src/pages/AboutPage/AboutPage.js
import { MetaTags } from '@redwoodjs/web'

const AboutPage = () => {
return (
<>
<MetaTags title="About" description="About page" />

<p>
This site was created to demonstrate my mastery of Redwood: Look on my
works, ye mighty, and despair!
</p>
</>
)
}

export default AboutPage

image

進捗しました!重複していた部分をすべて削除し、ヘッダコンテンツ(ロゴとナビゲーション)を一カ所にまとめました。

ここまでの作業はすべてWebサイド、つまりブラウザ上でのことです。それでは、バックエンドに着手して、GraphQL、Prisma、データベースをやっていきましょう。