Why does my component render 5 times when using RTK-query?

41 views Asked by At

i'm having problems with this component because it renders 5 times and I don't know why exactly, I've been reading about and it could be because of the RTK - query but I'm not sure how to fix it. I'll appreciate any help.

import { memo, useCallback, useEffect, useMemo, useState } from "react";
import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid";
import {
  Alert,
  Box,
  Button,
  Modal,
  Snackbar,
  TextField,
  Typography,
} from "@mui/material";
import { Add } from "@mui/icons-material";

import {
  useAddCategoryMutation,
  useEditCategoryMutation,
  useGetCategoriesQuery,
} from "../store/management/managementApi";
import { useForm } from "../hooks/useForm";

const EditToolbar = memo(({ setIsModalOpen }) => {
  const handleClick = () => {
    setIsModalOpen(true);
  };

  return (
    <GridToolbarContainer>
      <Button color="primary" startIcon={<Add />} onClick={handleClick}>
        Add Category
      </Button>
    </GridToolbarContainer>
  );
});

const initialForm = { name: "" };

export const CategoriesTable = () => {
  const { data, isLoading, isError } = useGetCategoriesQuery();
  const [editCategory, { error: editError }] = useEditCategoryMutation();
  const [addCategory, { error: addError }] = useAddCategoryMutation();
  const { name, onInputChange, onResetForm } = useForm(initialForm);

  const [rows, setRows] = useState([]);
  const [snackbar, setSnackbar] = useState(null);
  const [isModalOpen, setIsModalOpen] = useState(false);

  console.log(data);

  // Snackbar
  const handleCloseSnackbar = () => setSnackbar(null);

  // rows and colums
  const memoizedRows = useMemo(() => rows, [data?.content]);

  useEffect(() => {
    if (!isLoading && !isError && data !== undefined) {
      console.log("yes");
      setRows(data.content);
    }
  }, [data]);

  const colums = [
    { field: "name", headerName: "NAME", flex: 1, editable: true },
  ];

  // Table functions
  const processRowUpdate = useCallback(
    async (newRow, oldRow) => {
      if (newRow.name.trim() === oldRow.name) return oldRow;

      try {
        const response = await editCategory(newRow);

        if (response.data?.ok) {
          setSnackbar({
            children: "Changes saved successfully",
            severity: "success",
          });
          return response.data.content;
        } else {
          setSnackbar({ children: response.error.data.msg, severity: "error" });
          return oldRow;
        }
      } catch (error) {
        setSnackbar({
          children: editError.data.msg,
          severity: "error",
        });
        return oldRow;
      }
    },
    [editCategory]
  );

  // Modal functions
  const handleSubmit = useCallback(
    async (event) => {
      event.preventDefault();

      try {
        const response = await addCategory({ name: name });

        if (response.data?.ok) {
          const newRows = [...rows, response.data.content];
          setRows(newRows);

          setSnackbar({
            children: "Category saved successfully",
            severity: "success",
          });

          setIsModalOpen(false);
          onResetForm();
        } else {
          setSnackbar({ children: response.error.data.msg, severity: "error" });
          setIsModalOpen(false);
          onResetForm();
        }
      } catch (error) {
        setSnackbar({
          children: addError.data.msg,
          severity: "error",
        });
      }
    },
    [addCategory, name, onResetForm, rows]
  );

  const handleCloseModal = () => {
    setIsModalOpen(false);
    onResetForm();
  };

  const handleCancel = () => {
    setIsModalOpen(false);
    onResetForm();
  };

  return (
    <Box
      sx={{
        height: 500,
        width: "100%",
        "& .actions": {
          color: "text.secondary",
        },
        "& .textPrimary": {
          color: "text.primary",
        },
      }}
    >
      <Typography
        variant="h4"
        textTransform="uppercase"
        sx={{
          width: "100%",
          textAlign: "center",
          mb: "16px",
        }}
      >
        Categories
      </Typography>
      <DataGrid
        rows={rows}
        columns={colums}
        loading={isLoading}
        processRowUpdate={processRowUpdate}
        slots={{
          toolbar: EditToolbar,
        }}
        slotProps={{
          toolbar: { setIsModalOpen },
        }}
        sx={{ textTransform: "capitalize" }}
      />
      {!!snackbar && (
        <Snackbar
          open
          anchorOrigin={{
            vertical: "top",
            horizontal: "center",
          }}
          onClose={handleCloseSnackbar}
          autoHideDuration={6000}
        >
          <Alert
            {...snackbar}
            variant="filled"
            sx={{
              color: "white",
            }}
            onClose={handleCloseSnackbar}
          />
        </Snackbar>
      )}
      <Modal open={isModalOpen} onClose={handleCloseModal}>
        <Box
          sx={{
            position: "absolute",
            top: "50%",
            left: "50%",
            transform: "translate(-50%, -50%)",
            width: 400,
            bgcolor: "background.paper",
            border: "2px solid #000",
            boxShadow: 24,
            p: 4,
          }}
        >
          <Typography textTransform="uppercase">Add Category</Typography>
          <Box component="form" onSubmit={handleSubmit} sx={{ mt: 1 }}>
            <TextField
              margin="normal"
              required
              fullWidth
              id="name"
              label="Category Name"
              name="name"
              value={name}
              onChange={onInputChange}
            />
            <Box
              sx={{
                width: "100%",
                display: "flex",
                justifyContent: "space-between",
                gap: "8px",
              }}
            >
              <Button
                variant="outlined"
                fullWidth
                sx={{ mt: 3, mb: 2 }}
                onClick={handleCancel}
              >
                Cancel
              </Button>
              <Button
                type="submit"
                variant="contained"
                fullWidth
                sx={{ mt: 3, mb: 2 }}
              >
                Save
              </Button>
            </Box>
          </Box>
        </Box>
      </Modal>
    </Box>
  );
};

I've tried to move the query to the parent component but it made this one to have the same issue. they are exact 5 renders. Chrome Dev Tools

this is my rtk-query's endpoints configuration:

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { getEnvVariables } from "../../helpers/getEnvVariables";

const { VITE_API_URI } = getEnvVariables();

export const managementApi = createApi({
  reducerPath: "management",
  baseQuery: fetchBaseQuery({
    baseUrl: `${VITE_API_URI}/management`,
    prepareHeaders: (headers) => {
      const token = localStorage.getItem("token");

      if (token) {
        headers.set("x-token", token);
      }

      return headers;
    },
  }),
  tagTypes: ["Categories", "Products"],
  endpoints: (build) => ({
    getCategories: build.query({
      query: () => "/categories",
      providesTags: (result) =>
        result
          ? [
              ...result.content.map(({ id }) => ({ type: "Categories", id })),
              { type: "Categories", id: "LIST" },
            ]
          : [{ type: "Categories", id: "LIST" }],
    }),
    addCategory: build.mutation({
      query: (body) => ({
        url: "/categories/new",
        method: "POST",
        body,
      }),
      invalidatesTags: [{ type: "Categories", id: "LIST" }],
    }),
    editCategory: build.mutation({
      query: (body) => ({
        url: `categories/${body.id}`,
        method: "PUT",
        body,
      }),
      invalidatesTags: (result, error, { id }) => [{ type: "Categories", id }],
    }),
    deleteCategory: build.mutation({
      query: (id) => ({
        url: `/categories/${id}`,
        method: "DELETE",
      }),
      invalidatesTags: (result, error, id) => [{ type: "Categories", id }],
    }),
  }),
});

export const {
  useGetCategoriesQuery,
  useAddCategoryMutation,
  useEditCategoryMutation,
  useDeleteCategoryMutation,
} = managementApi;

For this app I'm using Reactjs, Redux-Tool-kit y materialUI

0

There are 0 answers