非同期処理を抱える構造のレビュー指針
はじめに
Reactアプリケーションのレビューで、特に注意して見たいのが非同期処理です。
fetch, setTimeout, WebSocket, dispatch(asyncThunk)… など、非同期のロジックがUIコンポーネント内にベタ書きされている構造は、レビューの重点ポイントになります。
この記事では、非同期処理を含む構造をどう見抜き、どう再構成すればよいのかを、レビューアー視点で具体的に解説します。
非同期処理が内包されている兆候
まずは、以下のようなコードがあれば構造的課題を疑ってよいです。
非同期処理が直接埋め込まれている例
export function UserInfo() {
  const [user, setUser] = useState(null);
  useEffect(() => {
    fetch('/api/user')
      .then(res => res.json())
      .then(setUser);
@Reviewer非同期通信を直接UIコンポーネントに書いてしまうと、構造の責務が曖昧になります。専用のHookや外部の処理モジュールに切り出すことを検討しましょう。  }, []);
  return <div>{user?.name}</div>;
}- API取得は副作用
 - UI層ではなくロジック層で持つべき
 - 将来的なエラー処理・再取得対応が難しくなる
 
よくある非同期処理の混在パターン
| パターン | 構造の課題 | 改善方向 | 
|---|---|---|
useEffect内にfetch直書き | 
UI責務とロジック責務の混在 | カスタムHookで分離 | 
onClickイベントにasync処理直書き | 
UIイベントとドメイン操作の密結合 | モジュール化 or useAsyncなどの抽象化 | 
| Redux dispatch(asyncThunk) を直接書く | 再利用しにくく、依存関係が不明瞭 | 処理サービス層に移譲 | 
構造分離の指針
パターン1:データ取得はCustom Hookへ
useUser.ts
export function useUser() {
  const [user, setUser] = useState(null);
  useEffect(() => {
    fetch('/api/user')
      .then(res => res.json())
      .then(setUser);
  }, []);
  return user;
}UserInfo.tsx
const user = useUser();
return <div>{user?.name}</div>;useUserの中で副作用を完結させ、UIから副作用を切り離す- テストや構造理解が圧倒的にしやすくなる
 
パターン2:非同期イベントはuseCallback+抽象モジュールへ
useSaveUser.ts
export async function saveUser(data) {
  const res = await fetch('/api/save', {
    method: 'POST',
    body: JSON.stringify(data),
  });
  return await res.json();
}ProfileForm.tsx
const handleSave = useCallback(async () => {
  const result = await saveUser(form);
  alert(result.status);
}, [form]);- UIイベントはあくまでトリガーのみ
 - 非同期の本体は抽象化された外部関数で定義
 
構造の違いを図示
構造的に非同期処理がUIから切り離されている後者の方が、責務の明確さ・拡張性・テスト容易性の面ですぐれています。
Redux環境でのレビュー観点
ReduxやRTK環境でも、dispatch(fetchUser()) のような記述が直接UIコンポーネント内にある場合、以下のような構造的問題が発生しやすいです。
- どのタイミングでdispatchされるかが隠蔽されやすい
 - 複数のdispatchが並列で走って順序があいまいになる
 - テスト時にstoreのモックが面倒になる
 
改善案
useFetchUser.ts
export const useFetchUser = () => {
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(fetchUser());
  }, [dispatch]);
};UserContainer.tsx
useFetchUser();
return <UserInfo />;このように、非同期のトリガー側をHookに閉じ込めるだけでも構造の明瞭さが増します。
レビューコメント例
非同期処理混在の指摘
@Reviewer: fetchをUI内に記述する構造は、責務の混在と再利用性の低下を招きます。useXxxの形で切り出し、処理の責務を明示的に分離しましょう。提案コメント例
- useEffect(() => { fetch(...); }, []);
+ const user = useUser();
まとめ
Reactで非同期処理を書くのは自然なことですが、それがUI構造と一体化してしまうと、コードの可読性・保守性が大きく下がります。
レビューアーとしては、「そのfetch、このコンポーネントで書くべき?」「非同期の流れが明確か?」という視点で、
責務の分離・構造の再設計を提案していくことが重要です。
非同期ロジックこそ、構造レビューで真っ先に見抜きたい設計要素のひとつです。

