Best way to handle CRUD in large-scale Next.js Projects With Redux Toolkit & RTK Query
Nadim Chowdhury
Posted on December 31, 2023
Handling CRUD operations in large-scale Next.js projects with Redux Toolkit for state management and Redux Toolkit Query for API fetching is a powerful combination. Below is a comprehensive guide on how to structure your project to efficiently manage state and API interactions:
Step 1: Project Structure
Organize your project for scalability. Consider a structure like the following:
- components/
- features/
- todos/
- todosSlice.js
- pages/
- api/
- todos.js
- queries/
- todos.js
- _app.js
- store.js
Step 2: Install Dependencies
npm install react-query axios @reduxjs/toolkit react-redux
Step 3: Configure Redux Toolkit and RTK Query
store.js
// store.js
import { configureStore } from '@reduxjs/toolkit';
import { setupListeners } from '@reduxjs/toolkit/query/react';
import { useDispatch } from 'react-redux';
import { createApi } from '@reduxjs/toolkit/query/react';
import { todosApi } from './queries/todos';
const store = configureStore({
reducer: {
[todosApi.reducerPath]: todosApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(todosApi.middleware),
});
setupListeners(store.dispatch);
export const useAppDispatch = () => useDispatch();
export default store;
queries/todos.js
// queries/todos.js
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
const API_URL = 'your_backend_api_url'; // Replace with your actual backend API URL
export const todosApi = createApi({
baseQuery: fetchBaseQuery({ baseUrl: API_URL }),
endpoints: (builder) => ({
getTodos: builder.query({
query: () => 'todos',
}),
addTodo: builder.mutation({
query: (newTodo) => ({
url: 'todos',
method: 'POST',
body: newTodo,
}),
}),
updateTodo: builder.mutation({
query: ({ id, text }) => ({
url: `todos/${id}`,
method: 'PUT',
body: { text },
}),
}),
deleteTodo: builder.mutation({
query: (id) => ({
url: `todos/${id}`,
method: 'DELETE',
}),
}),
}),
});
export const { useGetTodosQuery, useAddTodoMutation, useUpdateTodoMutation, useDeleteTodoMutation } = todosApi;
Step 4: Redux Toolkit Slice
features/todosSlice.js
// features/todosSlice.js
import { createSlice } from '@reduxjs/toolkit';
export const todosSlice = createSlice({
name: 'todos',
initialState: {
data: [],
},
reducers: {
setTodos: (state, action) => {
state.data = action.payload;
},
addTodo: (state, action) => {
state.data.push(action.payload);
},
updateTodo: (state, action) => {
const { id, text } = action.payload;
const index = state.data.findIndex((todo) => todo.id === id);
if (index !== -1) {
state.data[index].text = text;
}
},
deleteTodo: (state, action) => {
const id = action.payload;
state.data = state.data.filter((todo) => todo.id !== id);
},
},
});
export const { setTodos, addTodo, updateTodo, deleteTodo } = todosSlice.actions;
export default todosSlice.reducer;
Step 5: Components
components/TodoList.js
// components/TodoList.js
import React from 'react';
import { useGetTodosQuery, useAddTodoMutation, useUpdateTodoMutation, useDeleteTodoMutation } from '../queries/todos';
import { useDispatch } from 'react-redux';
import { setTodos, addTodo, updateTodo, deleteTodo } from '../features/todosSlice';
const TodoList = () => {
const dispatch = useDispatch();
const { data: todos, isLoading } = useGetTodosQuery();
const addTodoMutation = useAddTodoMutation();
const updateTodoMutation = useUpdateTodoMutation();
const deleteTodoMutation = useDeleteTodoMutation();
const handleAddTodo = async () => {
const newTodo = { text: 'New Todo' };
const response = await addTodoMutation.mutateAsync(newTodo);
dispatch(addTodo(response));
};
const handleUpdateTodo = async (id, newText) => {
const response = await updateTodoMutation.mutateAsync({ id, text: newText });
dispatch(updateTodo(response));
};
const handleDeleteTodo = async (id) => {
await deleteTodoMutation.mutateAsync(id);
dispatch(deleteTodo(id));
};
if (isLoading) {
return <div>Loading...</div>;
}
return (
<div>
<h1>Todo App</h1>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
{todo.text}{' '}
<button onClick={() => handleUpdateTodo(todo.id, 'Updated Todo')}>Update</button>
<button onClick={() => handleDeleteTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
<button onClick={handleAddTodo}>Add Todo</button>
</div>
);
};
export default TodoList;
Conclusion:
This structure separates concerns, making it easier to manage and scale your application. Redux Toolkit Query handles data fetching and caching, while Redux Toolkit handles state management. This setup allows for better maintainability and scalability in large-scale Next.js projects. Adjust the code based on your specific requirements and backend API structure.
If you enjoy my content and would like to support my work, you can buy me a coffee. Your support is greatly appreciated!
Disclaimer: This content has been generated by AI.
Posted on December 31, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024