DEV Community

Nadim Chowdhury
Nadim Chowdhury

Posted on โ€ข Edited on

1

Best way to handle CRUD in large-scale Next.js Projects With Redux Toolkit & RTK Query

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
Enter fullscreen mode Exit fullscreen mode

Step 2: Install Dependencies

npm install react-query axios @reduxjs/toolkit react-redux
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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.

Support My Work โค๏ธ

If you enjoy my content and find it valuable, consider supporting me by buying me a coffee. Your support helps me continue creating and sharing useful resources. Thank you!

Connect with Me ๐ŸŒ

Letโ€™s stay connected! You can follow me or reach out on these platforms:

๐Ÿ”น YouTube โ€“ Tutorials, insights & tech content

๐Ÿ”น LinkedIn โ€“ Professional updates & networking

๐Ÿ”น GitHub โ€“ My open-source projects & contributions

๐Ÿ”น Instagram โ€“ Behind-the-scenes & personal updates

๐Ÿ”น X (formerly Twitter) โ€“ Quick thoughts & tech discussions

Iโ€™d love to hear from youโ€”whether itโ€™s feedback, collaboration ideas, or just a friendly hello!

Disclaimer

This content has been generated with the assistance of AI. While I strive for accuracy and quality, please verify critical information independently.

Top comments (0)