React Redux データフェッチ ローディング 表示
- Redux ストアにローディング状態を追加する
- データフェッチアクションを作成する
- Reducer でローディング状態を更新する
- コンポーネントでローディング状態をチェックしてインジケーターを表示する
詳細な手順
まず、Redux ストアにローディング状態を追加します。この状態は、データのフェッチが進行中かどうかを示します。
// store/initialState.js
const initialState = {
isLoading: false,
data: [],
error: null,
};
次に、データフェッチのアクションを作成します。このアクションは、API からデータを取得し、成功または失敗に応じてローディング状態を更新します。
// actions/fetchData.js
export const fetchData = () => async (dispatch) => {
dispatch({ type: 'FETCH_DATA_REQUEST' });
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
dispatch({ type: 'FETCH_DATA_SUCCESS', payload: data });
} catch (error) {
dispatch({ type: ' FETCH_DATA_FAILURE', payload: e rror });
}
};
Reducer は、アクションに応じてストアの状態を更新します。データフェッチのアクションに対して、ローディング状態を true
に設定し、成功または失敗に応じて false
に戻します。
// reducers/dataReducer.js
export default function dataReducer(state = initialState, action) {
switch (action.type) {
case 'FETCH_DATA_REQUEST':
return { ...state, is Loading: true };
case 'FETCH_DATA_SUCCESS':
return { ...state, isLoading: false, data: action.payload };
case 'FETCH_DATA_FAILURE':
return { ...state, isLoading: false, error: action.payload };
default:
return state ;
}
}
// components/DataComponent.js
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fet chData } from '../actions/fetchDat a';
function DataComponent() {
const dispatch = useDispatch();
const { isLoading, data, error } = useSelector((state) => state.data);
useEffect(() => {
dispatch(fetchData());
}, [dispatch]);
if (isLoading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
return (
<div>
{data.map((item) => (
<p key={item.id}>{item.name}</p>
))}
</div>
);
}
export default DataComponent;
- Redux Toolkit を使用すると、より簡潔にデータフェッチとローディング状態の管理を行うことができます。
- より複雑なアプリケーションでは、複数のデータフェッチを行う場合、それぞれのフェッチに対してローディング状態を管理する必要があります。
- エラーハンドリングも適切に行う必要があります。
- ローディングインジケーターのデザインは自由にカスタマイズできます。
// store/initialState.js
const initialState = {
isLoading: false,
data: [],
error: null,
};
error
: エラーが発生した場合に格納されるオブジェクト。data
: フェッチされたデータが格納される配列。isLoading
: データのフェッチが進行中かどうかを示すフラグ。初期値はfalse
。
// actions/fetchData.js
export const fetchData = () => async (dispatch) => {
dispatch({ type: 'FETCH_DATA_REQUEST' });
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
dispatch({ type: 'FETCH_DATA_SUCCESS', payload: data });
} catch (error) {
dispatch({ type: ' FETCH_DATA_FAILURE', payload: e rror });
}
};
FETCH_DATA_FAILURE
: データフェッチが失敗したことを示すアクション。payload
にはエラーオブジェクトが含まれる。FETCH_DATA_REQUEST
: データフェッチを開始したことを示すアクション。
// reducers/dataReducer.js
export default function dataReducer(state = initialState, action) {
switch (action.type) {
case 'FETCH_DATA_REQUEST':
return { ...state, is Loading: true };
case 'FETCH_DATA_SUCCESS':
return { ...state, isLoading: false, data: action.payload };
case 'FETCH_DATA_FAILURE':
return { ...state, isLoading: false, error: action.payload };
default:
return state ;
}
}
FETCH_DATA_FAILURE
:isLoading
をfalse
に設定し、error
にエラーオブジェクトを格納する。FETCH_DATA_SUCCESS
:isLoading
をfalse
に設定し、data
に取得したデータを格納する。FETCH_DATA_REQUEST
:isLoading
をtrue
に設定して、ローディングを開始する。
// components/DataComponent.js
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fet chData } from '../actions/fetchDat a';
function DataComponent() {
const dispatch = useDispatch();
const { isLoading, data, error } = useSelector((state) => state.data);
useEffect(() => {
dispatch(fetchData());
}, [dispatch]);
if (isLoading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
return (
<div>
{data.map((item) => (
<p key={item.id}>{item.name}</p>
))}
</div>
);
}
export default DataComponent;
data
: データがフェッチされた場合、データをレンダリング。error
: エラーが発生した場合、エラーメッセージを表示。isLoading
: ローディング状態をチェック。true
の場合、ローディングインジケーターを表示。useEffect
: コンポーネントがマウントされたときにfetchData
アクションをディスパッチする。
- デメリット
複雑なロジックの場合、フック自体が複雑になる可能性がある。 - メリット
コードの再利用性が高まる。
import { useState, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchData } from '../actions/fetchData';
const useFetchData = () => {
const dispatch = useDispatch();
const { isLoading, data, error } = useSelector((state) => state.data);
useEffect(() => {
dispatch(fetchData());
}, [dispatch]);
return { isLoading, data, error };
};
// ...
function DataComponent() {
const { isLoading, data, error } = useFetchData();
// ...
}
Redux Toolkit
- デメリット
学習曲線がある。 - メリット
簡潔なコード、より強力な機能。
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
export const fetchData = createAsyncThunk('data/fetchData', async () => {
const res ponse = await fetch('https://api.example.com/data');
return response.json();
});
const dataSlice = createSlice({
name: 'data',
initialState: {
isLoading: false,
data: [],
error: null,
},
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchData.pending, (state) => {
state.isLoading = true;
})
.addCase(fetchData.fulfi lled, (state, action) => {
state.isLoading = false;
state.data = action.payload;
})
.addCase(fetchData.rejected, (stat e, action) => {
state.isLoading = false;
state.error = action.error.message;
});
},
});
export default dataSlice. reducer;
Third-party Libraries
-
React Query
- 自動的にデータのフェッチ、キャッシュ、更新を行う。
- ローディング状態、エラーハンドリング、再試行などの機能を提供。
import { useQuery } from 'react-query';
const fetchData = async () => {
const response = await fetch('https://api.example.com/data');
return response.json();
};
function DataComponent() {
const { isLoading, data, error } = useQuery('data', fetchData);
// ...
}
選択のポイント
- パフォーマンス要件
高パフォーマンスが必要な場合は、React Query のような最適化されたライブラリが有用。 - チームのスキルと好み
チームのメンバーの Redux Toolkit や React Query の熟練度を考慮。 - プロジェクトの規模と複雑さ
小規模なプロジェクトでは、基本的な Redux アプローチで十分。大規模なプロジェクトでは、Redux Toolkit や React Query のようなツールを使うと効率的。
javascript reactjs redux