useContextでHttpClient(axios)を共有するサンプル

axios などでプロジェクト全体に共通するインターセプターを定義しておくことで、認証やエラーハンドリングなどの処理を一元化できます。

1. AxiosContext を作成

// libs/axios/AxiosContext.tsx
import axios, { AxiosInstance } from 'axios';
import { createContext, useContext, useMemo, ReactNode } from 'react';

const AxiosContext = createContext<AxiosInstance | null>(null);

const createAxiosInstance = (): AxiosInstance => {
  const instance = axios.create({
    baseURL: 'https://api.example.com',
    headers: { 'Content-Type': 'application/json' },
  });

  // 🔐 リクエストインターセプター: JWTトークンを付与
  instance.interceptors.request.use(
    (config) => {
      const token = localStorage.getItem('jwt_token');
      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      }
      return config;
    },
    (error) => Promise.reject(error)
  );

  // ❗️レスポンスインターセプター: 共通エラーハンドリング
  instance.interceptors.response.use(
    (response) => response,
    (error) => {
      if (error.response) {
        const { status } = error.response;

                if (status >= 500) {
          console.error('サーバーエラー共通ハンドリング');
        }
      }
      return Promise.reject(error);
    }
  );

  return instance;
};

export const AxiosProvider = ({ children }: { children: ReactNode }) => {
  const axiosInstance = useMemo(() => createAxiosInstance(), []);
  return (
    <AxiosContext.Provider value={axiosInstance}>
      {children}
    </AxiosContext.Provider>
  );
};

export const useAxios = (): AxiosInstance => {
  const context = useContext(AxiosContext);
  if (!context) {
    throw new Error('useAxios must be used within an AxiosProvider');
  }
  return context;
};

2. Service Hook を定義

export const useUserService = () => {
  const axios = useAxios();

  const [users, setUsers] = useState<User[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const fetchUsers = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const res = await axios.get<User[]>('/users');
      setUsers(res.data);
    } catch (err: any) {
      setError(err.message || '取得失敗');
    } finally {
      setLoading(false);
    }
  }, [axios]);

  return { users, loading, error, fetchUsers };
};

UIコンポーネントでの実装

// components/UserList.tsx
import { useUserService } from '../services/useUserService';
import { useEffect } from 'react';

export const UserList = () => {
  const { users, loading, error, fetchUsers } = useUserService();

  useEffect(() => {
    fetchUsers();
  }, [fetchUsers]);

  if (loading) return 
<p>読み込み中...</p>;
  if (error) return 
<p>エラー: {error}</p>;

  return (

<div>

<h2>ユーザー一覧</h2>

<ul>
        {users.map(user => (
          <li key={user.id}>{user.name} ({user.email})</li>
        ))}
      </ul>
    </div>
  );
};

Providerの設定

// App.tsx
import { AxiosProvider } from './libs/axios/AxiosContext';
import { UserList } from './components/UserList';

export const App = () => (

<AxiosProvider>
    <UserList />
  </AxiosProvider>
);
コメントを残す 0

Your email address will not be published. Required fields are marked *