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>
);