dbd_fish
@dbd_fish

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

RemixのLoader関数の共通化について

Discussion

解決したいこと

RemixにおけるLoader関数の設計について教えて頂きたいです。
Remixでは各ルーティングごとにLoader関数を定義しますが、一部の処理は同じロジックになるため、共通化を検討しています。
私は共通する処理を別ディレクトリに格納して呼び出す設計で作成しました。

Loader関数の共通化について、実際の仕事ではどのように設計しているか?などのアドバイスをいただきたいです。
よろしくお願いいたします。

↓作りかけですが、Githubはこちらです。
https://github.com/dbd-fish/react_sample

対象コード

↓Loader関数

sample_remix_react/app/routes/mypage.tsx
import { LoaderFunction, redirect } from '@remix-run/node';

import { userDataLoader } from '../loader/userDataLoader';
import {
  AuthenticationError,
  authTokenLoader,
} from '../loader/authTokenLoader';

export const loader: LoaderFunction = async ({ request }) => {
  try {
    await authTokenLoader(request);
    const userData = await userDataLoader(request);

    return new Response(JSON.stringify(userData), {
      headers: { 'Content-Type': 'application/json' },
    });
  } catch (error) {
    if (error instanceof AuthenticationError) {
      console.log('Loader: AuthenticationError:');
      return redirect('/login');
    }
    console.error('Loader Error:', error);

    throw new Response('ユーザーデータの取得に失敗しました。', {
      status: 400,
    });
  }
};

export default function MyPage() {
    // 省略
}

↓Loader関数から呼び出す共通処理authTokenLoader()

sample_remix_react/app/loader/authTokenLoader.tsx

export class AuthenticationError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'AuthenticationError';
  }
}

export async function authTokenLoader(request: Request) {
  // HTTP-only クッキーの取得
  const cookieHeader = request.headers.get('Cookie');
  console.log('Loader: Incoming cookies:', cookieHeader);

  // authToken と csrfToken をクッキーから抽出
  const authTokenMatch = cookieHeader?.match(/authToken=([^;]+)/);
  const csrfTokenMatch = cookieHeader?.match(/csrftoken=([^;]+)/);

  const authToken = authTokenMatch ? authTokenMatch[1] : null;
  const csrfToken = csrfTokenMatch ? csrfTokenMatch[1] : null;

  console.log('Loader: Extracted authToken:', authToken);
  console.log('Loader: Extracted csrfToken:', csrfToken);

  // authToken が存在しない場合はログインページへリダイレクト
  if (!authToken) {
    console.log('Loader: Missing authToken, redirecting to login.');
    throw new AuthenticationError('認証トークンが見つかりません。');
  }

  return;
}

↓Loader関数から呼び出す共通処理userDataLoader()

sample_remix_react/app/loader/userDataLoader.tsx

import { fetchUserData } from '../utils/api/fetchUserData';

export async function userDataLoader(request: Request) {
  // 外部API呼び出し
  console.log('Loader: Fetching user data with authToken...');
  const userData = await fetchUserData(request);
  console.log('Loader: Retrieved user data:', userData);

  return userData;
}


0

Your answer might help someone💌