Remixでページ遷移の時にprogress bar(インスタ風)を表示させる

2022/05/20に公開

next.JSの場合はライブラリが存在しますが、remixはまだオープンソースに公開されたばかりなので、ここら辺のライブラリがまだ充実してない感じですよね、結構探してもあまり情報が出て来なかったので、自分で公式documentationを読みながら多分こうしたらいけるであろう方法で作ってみたので、シェアしておきたいなと思います。

※ remixもまだ触ったばかりなので、詳しい方がいたらコメント頂けると助かります🙌

試したこと

  • History API
    remixはnextjsと違ってページが再読み込みされるみたいなので、ブラウザーの history APIにListenerを登録しておいて、ロジックを実装するといった方法ではだめでした。

どうする

公式を探っていたら、useTransitionというhookがありました。
formを送信した後の判定に使ったりするみたいですが、もう少し詳しく見てみるとhookで帰ってくる値 trasnsition.state にいくつの状態があるみたいです👇。

  • idle - There is no transition pending.
  • submitting - A form has been submitted. If GET, then the route loader is being called. If POST, PUT, PATCH, DELETE, then the route action is being called.
  • loading - The loaders for the next routes are being called to render the next page.

正に loading ですね!

実装

そのままroot.tsxに処理追加します。

root.tsx

import {
  Links,
  LiveReload,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
  useTransition,
} from '@remix-run/react';
import ProgressBar from './components/ProgressBar';

export default function App() {
  const transition = useTransition(); // 👈ここ
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1" />
      </head>
      <body>
        <Outlet />
        <ScrollRestoration />
        <Scripts />
        {process.env.NODE_ENV === 'development' && <LiveReload />}
        {transition.state === 'loading' && <ProgressBar />} // 👈ここ
      </body>
    </html>
  );
}

おまけ

web版のインスタグラム風のprogress barの実装(emotion使っています)

ProgressBar.tsx

import { css, keyframes } from "@emotion/css";

const postDiverAnimation = keyframes`
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
`;

const progressInAnimation = keyframes`
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0);
  }
`;

const ProgressBar = () => (
  <div
    className={css`
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      z-index: 100;
      height: 3px;
      background: #27c4f5
        linear-gradient(to right, #27c4f5, #a307ba, #fd8d32, #58c322, #27c4f5);
      width: 100%;
      background-size: 200% 200%;
      animation: ${postDiverAnimation} 2s linear infinite,
        ${progressInAnimation} 1s ease-in-out;
    `}
  ></div>
);

export default ProgressBar;


インスタグラムは👇こんなに感じですね。

インスタグラムのprogress barの画像

デモ

Discussion