😎

Remix のチュートリアルをやってみた - Developers Blog 編

2022/02/18に公開

はじめに

Remix という Next.js や Gatsby 的な React ライブラリがいまノリにノッているらしい。 "Remix" なだけに
違いは何か、他と比べて何が優れているのか、は丁寧に紹介されている先輩方の記事を参照されたし

どんなかんじなのか、公式のチュートリアルを読みながら手を動かしてみた

思ったこと 3 つ

  • データフェッチが Next.js よりスッキリ書けそう
  • メタデータをページごとに定義できる柔軟性があるが、僕のような初心者では取りこぼしをしそうで怖い
  • Nested Routes という Remix ならではの機能。使いこなせれば強力な味方になりそうだ

チュートリアルやってみて備忘録

これにチャレンジ

https://remix.run/docs/en/v1/tutorials/blog

ルーティング

app/routes 以下のディレクトリ名やファイル名が URL のパス名に一致する
ダイナミックなルーティングは $filename.tsx という感じの名前にする ( 頭に $ をつける )

app/routes/index.tsx -> localhost:3000
app/routes/posts/index.tsx -> localhost:3000/posts
app/routes/posts/$slug.tsx -> localhost:3000/posts/your-slug-name

データローディング

loader() という関数内でデータフェッチをする
デフォルト関数内で useLoaderData() をすると loader() 内で return したデータを取れる

//...
export const loader = async () => {
  return getPosts();
};

export default function Posts() {
  const posts = useLoaderData<Post[]>();
//...

import 時のファイルパス

app/ 以下を ~/ で表している

app/post.ts -> ~/post

( 追記 ) これは tsconfig.json の設定だった。プロジェクトのデフォルトでそういうことにしたようだ

params の取り方

loader() を使う
app/route/posts/$slug.tsxslug を取得したいときは

import type { LoaderFunction } from "remix";

export const loader: LoaderFunction = async ({ params }) => {
  return params.slug;
}

export default function PostSlug() {
  const slug = useLoaderData();
  return (
    <div>
      <h1>{slug}</h1>
    </div>
  )
}

TypeScript で引数 params の型を特定するために loader に明示的に LoaderFunction 型を指定している

CSS を使う

Remix では各ページで <link> を埋め込むような形で CSS を使える。ページごとに別々の CSS を埋め込める反面、共通化するならそういうやり方を考えないといけなさそう

import adminStyles from "~/styles/admin.css"

export const links = () => {
  return [{ rel: "stylesheet", href: adminStyles }]
}

// -> <link rel="stylesheet" href="...">

<link> 以外にもいろいろな meta タグをページごとに埋め込める

nested routes

Remix の特徴的な機能。ルートモジュール — Next.js でいうところのページコンポーネント — を入れ子にできる
データフェッチやエラーは各ルートモジュール内で完結していて、子のルートモジュールがエラーであってもその部分だけがエラーになり、親ルートモジュールはちゃんと表示される

app/routes/admin.tsx
app/routes/admin/index.tsx
app/routes/admin/new.tsx

こんな構成でファイルを作ったときに admin.tsx が親ルートモジュールとなり、 admin/ 以下の各ページは admin.tsx 側にポータルのようなもの ( Outlet ) を設置することで admin.tsx の中でコンポーネントのように表示ができる

app/routes/admin.tsx
import { Outlet, ... } from "remix"

//...
<nav>...</nav>
<main>
  <Outlet />
</main>

// -> app/routes/admin/ 以下のページをパス名に応じて Outlet の場所に出すことができる

app/routes/admin/index.tsx を表示している
app/routes/admin/index.tsx を表示している

app/routes/admin/new.tsx を表示している
app/routes/admin/new.tsx を表示している

ヘッダー > サイドバー > ナビゲーションタブ
といった入れ子構造のページの場合に nested routes は有効。データフェッチやエラーハンドリングは一番親から降っていく必要はない

アクション

データのポストは remix の Formaction()useActionData() を使う
HTML の form のように中で inputsubmit を組み立てる
submit した内容は action()request として受けて中で DB に保存したり必要な処理をする
action() の中で条件によって error オブジェクトを返した場合、ページコンポーネントの中で

errors = useActionData()

とすればエラー時の処理を行える

まとめ

はじめてさわってみたのでまだメリデメを見いだせていない。たくさんの素晴らしい機能のほんの一部だけしか見えていない。継続して調査を進めようと思う
次回は Jokes App に挑戦したいと思う

Discussion