npm install @reduxjs/toolkit react-redux
・src/providers/ReduxProvider.tsx
・src/stores/myApi.ts
・src/stores/store.ts
src/providers/ReduxProvider.tsx
'use client';
import React from 'react';
import { store } from '../stores/store';
import { Provider } from 'react-redux';
export const ReduxProvider = (props: React.PropsWithChildren) => {
return <Provider store={store}>{props.children}</Provider>;
};
src/store.ts
import { configureStore } from '@reduxjs/toolkit';
import { myApi } from './myApi';
import { setupListeners } from '@reduxjs/toolkit/query';
export const store = configureStore({
reducer: {
[myApi.reducerPath]: myApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(myApi.middleware),
});
setupListeners(store.dispatch);
src/stores/myApi.ts
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
type People = {
name: string;
height: string;
mass: string;
};
export const myApi = createApi({
reducerPath: 'myApi',
baseQuery: fetchBaseQuery({ baseUrl: 'https://swapi.dev/api/' }),
endpoints: (builder) => ({
getPeople: builder.query<People, string>({
query: (id) => `people/${id}`,
}),
}),
});
export const { useGetPeopleQuery } = myApi;
src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import './index.css';
import { ReduxProvider } from './providers/ReduxProvider.tsx';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<ReduxProvider>
<App />
</ReduxProvider>
</React.StrictMode>
);
src/App.tsx
import './App.css';
import { useGetPeopleQuery } from './stores/myApi';
function App() {
const { data, isLoading } = useGetPeopleQuery('2');
return (
<>
<h1>sample</h1>
{isLoading && <div>Loading...</div>}
<div>{JSON.stringify(data)}</div>
</>
);
}
export default App;
エラーログを表示するミドルウェアを作成してみます。
src/middlewares/errorLogMiddleware.ts
import {
Middleware,
isRejectedWithValue,
MiddlewareAPI,
} from '@reduxjs/toolkit';
import { FetchBaseQueryError } from '@reduxjs/toolkit/query';
type EventData = {
eventCategory: string;
eventAction: string;
eventLabel: string;
};
export const errorLogMiddleware: Middleware =
(_: MiddlewareAPI) => (next) => (action) => {
if (isRejectedWithValue(action)) {
const errorPayload = action.payload as FetchBaseQueryError;
const errorData: string = errorPayload.data as string;
// エラー情報からイベントデータを作成
const eventData: EventData = {
eventCategory: 'API Error',
eventAction: errorPayload.status as string,
eventLabel: errorData,
};
// エラーを表示
console.error('● eventData');
console.error(eventData);
}
return next(action);
};
src/stores/store.ts
import { configureStore } from '@reduxjs/toolkit';
import { myApi } from './myApi';
import { setupListeners } from '@reduxjs/toolkit/query';
import { errorLogMiddleware } from '../middlewares/errorLogMiddleware';
export const store = configureStore({
reducer: {
[myApi.reducerPath]: myApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(myApi.middleware).concat(errorLogMiddleware),
});
setupListeners(store.dispatch);
その他参考 :
https://qiita.com/7tsuno/items/2301a35283db7cd54df9
https://zenn.dev/snamiki1212/scraps/3c7190317c5e8f