Next.js Discord

Discord Forum

Material UI tabs navigation

Unanswered
Acacia-ants posted this in #help-forum
Open in Discord
Acacia-antsOP
Hey guys. I have a strange problem with our webapp, I have a screen with material ui tabs. Normally switching between them don't take too much time but when I open one of the modals which stays on screen when changing tabs it's taking long time. Take a look on videos. Do you have any idea what's wrong here?

86 Replies

Material hi is heavy code wise. You’re going to have to provide code to get assistance.
Acacia-antsOP
Hey thanks for answering. I digged in a little bit in. The problem is that one part of modal is using few components with react context. When I comment this part it start to working fine
Do you have any idea why it can cause a problem?
this whole part
when I comment out this part like this
the problem is still appearing
in CategoriesWatcher I've got this code
import Loading from "@app/loading";
import { getCaseTypeAndCategories, useAppSelector } from "@app/redux";
import { getCategoryDetails } from "@app/settings/categories/(common)/actions";
import { CategoryAddEdit, Maybe } from "@app/types";
import { hookFactory, useServerQuery } from "@app/utils/hooks";
import React from "react";
import { getCategoryId } from "../form-state/helpers";
import { AdditionalDetailsWatcher } from "../additional-details-watcher/additional-details-watcher";

type CategoryWatcherCtx = {
  isPending: false;
  data: Maybe<CategoryAddEdit>;
};

const ctx = React.createContext<CategoryWatcherCtx>({
  data: null,
  isPending: false
});

export const useCategoriesWatcher = hookFactory({
  ctx,
  hookName: "useCategoriesWatcher",
  providerName: "CategoriesWatcher"
});

type CategoriesWatcherProps = {
  children: React.ReactNode;
  renderLoader?: () => JSX.Element;
};

export const CategoriesWatcher = ({ children, renderLoader = () => <Loading /> }: CategoriesWatcherProps) => {
  const caseTypeAndCategories = useAppSelector(getCaseTypeAndCategories);

  const { data, isPending } = useServerQuery<CategoryAddEdit>({
    action: async () => {
      if (!caseTypeAndCategories) return;
      const categoryId = getCategoryId(caseTypeAndCategories);

      return getCategoryDetails(categoryId);
    }
  });

  if (isPending) {
    return renderLoader();
  }

  return (
    <AdditionalDetailsWatcher additionalDetailsTabs={data?.additionalDetailsTabs || []}>
      <ctx.Provider value={{ data, isPending }}>{children}</ctx.Provider>
    </AdditionalDetailsWatcher>
  );
};
and this AdditionalDetailsWatcher
Lewis's Woodpecker
tip: use
```js
<code_here>
```
to have syntax highlighting
Acacia-antsOP
yeah yeah I found out thanks 😄
what is funny, when I replace data response in CategoriesWatcher to empty object {}, remove loader etc AND in AdditionalDetailsWatcher I will also pass empty value to Provider it's still the same
Did you try memoizing the component?
Acacia-antsOP
Yeah I memoized these values passed to context
@Acacia-ants when I comment out this part like this
Acacia-antsOP
ok I already sent these two components so let me show you full code and you will catch something
Are you fetching something on these tabs ?
Acacia-antsOP
yep of course
but without opened modal It's like instan redirect
Do you keep values in a store ?
Acacia-antsOP
redux?
not necessarily
it can be any of store lib or react context
Acacia-antsOP
Actually each tab is page.tsx where I'm using server action to fetch data = one or two requests
and passing them to client components where I have UI etc
I guess your fetch taking time and thats why
Acacia-antsOP
ok but why when I don't have modal is totally fine
even when I open other modal (I have few of them) it's totally fine
let me record some video quickly
Oh
I havent seen the 2nd video
my bad
Acacia-antsOP
Yeah yeah
Uhm there is another issue there. When your modal isnt open and you're switching you have a fallback display (spinner loading)
Acacia-antsOP
without this particular modal it's totally fine, I opened others and tried to switch tabs and redirect is instant and than I can see loading for them
when your modal is open you dont have it
Acacia-antsOP
I have it, let me record one thing
look, when I have modal opened and trying to switch tab, it causing a freeze
on Contact Details tab it's a freeze + quick request
Can you share the project structure please ?
Acacia-antsOP
but on Links I have some more data to fetch so it showing loading idicator after that freeze
what do you exactly need?
How you organize files
your pages and the modal
where are they located
Acacia-antsOP
So I have a page folder called case-details/[id] inside of it I have layout.tsx like this
"use client";
import Box from "@mui/material/Box";
import React from "react";
import { CaseOptionDialogs } from "./components/case-option-dialogs";
import { CategoriesTabs } from "./components/categories-tabs";
import { NotesGrid } from "./details/notes-grid";

const CategoriesLayout = ({ children }: { children: React.ReactNode }) => {
  return (
    <>
      <Box sx={{ width: "100%" }}>
        <CategoriesTabs />
        <CaseOptionDialogs />
        {children}
        <NotesGrid />
      </Box>
    </>
  );
};

export default CategoriesLayout;
Let me just copy paste your code to have code style its more lisible
import Loading from "@app/loading";
import { getCaseTypeAndCategories, useAppSelector } from "@app/redux";
import { getCategoryDetails } from "@app/settings/categories/(common)/actions";
import { CategoryAddEdit, Maybe } from "@app/types";
import { hookFactory, useServerQuery } from "@app/utils/hooks";
import React from "react";
import { getCategoryId } from "../form-state/helpers";
import { AdditionalDetailsWatcher } from "../additional-details-watcher/additional-details-watcher";

type CategoryWatcherCtx = {
  isPending: false;
  data: Maybe<CategoryAddEdit>;
};

const ctx = React.createContext<CategoryWatcherCtx>({
  data: null,
  isPending: false
});

export const useCategoriesWatcher = hookFactory({
  ctx,
  hookName: "useCategoriesWatcher",
  providerName: "CategoriesWatcher"
});

type CategoriesWatcherProps = {
  children: React.ReactNode;
  renderLoader?: () => JSX.Element;
};

export const CategoriesWatcher = ({ children, renderLoader = () => <Loading /> }: CategoriesWatcherProps) => {
  const caseTypeAndCategories = useAppSelector(getCaseTypeAndCategories);

  const { data, isPending } = useServerQuery<CategoryAddEdit>({
    action: async () => {
      if (!caseTypeAndCategories) return;
      const categoryId = getCategoryId(caseTypeAndCategories);

      return getCategoryDetails(categoryId);
    }
  });

  if (isPending) {
    return renderLoader();
  }

  return (
    <AdditionalDetailsWatcher additionalDetailsTabs={data?.additionalDetailsTabs || []}>
      <ctx.Provider value={{ data, isPending }}>{children}</ctx.Provider>
    </AdditionalDetailsWatcher>
  );
};
Acacia-antsOP
{children} is loading each page.tsx inside this main page folder yeah
Can you share your main layout ?
Acacia-antsOP
you mean this highest one in hierarchy
Well not needed i guess
Whats the categories watcher and Links state provider ?
Acacia-antsOP
and this is an example tab/page, others are similar 1-2 server actions there
import Grid from "@mui/material/Grid";
import { getCaseLinks } from "../(common)/actions";
import { LinksDetails } from "./details";

type DetailsProps = {
  params: {
    id: number;
  };
};

export default async function Details({ params }: DetailsProps) {
  const id = params?.id;
  const linkDetails = await getCaseLinks(id);
  return (
    <Grid container spacing={2} justifyContent="flex-end">
      <Grid item xs={12}>
        <LinksDetails linksDetails={linkDetails} />
      </Grid>
    </Grid>
  );
}
there is a logic in our application where we are displaying these links based on created item, it's for bussiness implementation
you need to have X to be able to see Link A, Link B etc
you know what I mean
all files used in these manage-links modal
Which file is used for modal?
Acacia-antsOP
Components named like in files which I sent
The issue is coming from your Modal and how its shared. You may investigate on this
Acacia-antsOP
what do you mean?
Dialog component and grid component
Your issue is only when modal is open right ?
Acacia-antsOP
but you know, I was testing it and commented out this whole strucate with CategoryWatcher and it started working fine
yeah
I cannot help much I'm a bit lost in your code :/
Acacia-antsOP
ok give me a minute I will try to do one more thing
Acacia-antsOP
ok I have an update
  const caseTypeAndCategories = useAppSelector(getCaseTypeAndCategories);
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
redux useSelector
any idea how to take care of it?
Acacia-antsOP
@ItetsuLaTable
is getCaseTypeAndCategories a function ?
because its seems like a function but you're not calling it with ()
Acacia-antsOP
export const getCaseTypeAndCategories = (state: RootState) => state.addCaseReducer.caseTypeAndCategorySelection;
it's a getter function
Acacia-antsOP
I tried to memoize it somehow but still the same
export const CategoriesWatcher = ({ children, renderLoader = () => <Loading /> }: CategoriesWatcherProps) => {
  const caseTypeAndCategories = useAppSelector(getCaseTypeAndCategories);

  const categoryId = useMemo(() => {
    if (!caseTypeAndCategories) return null;
    return getCategoryId(caseTypeAndCategories);
  }, [caseTypeAndCategories]);

  const { data, isPending } = useServerQuery<CategoryAddEdit>({
    action: async () => {
      if (!categoryId) return;
      return getCategoryDetails(categoryId);
    },
    deps: [categoryId]
  });

  if (isPending) {
    return renderLoader();
  }

  return (
    <AdditionalDetailsWatcher additionalDetailsTabs={data?.additionalDetailsTabs || []}>
      <ctx.Provider value={{ data, isPending }}>{children}</ctx.Provider>
    </AdditionalDetailsWatcher>
  );
};