Next.js Discord

Discord Forum

Next and use() causing infinite requests.

Answered
Bombay-duck posted this in #help-forum
Open in Discord
Bombay-duckOP
Hi there. I’m encountering an error in my NextJS app. For some background, I am loading some data from FireBase based on an ID. Here is my page component:
export default function ProjectPage() {
  console.log("Loading project page");
  const params = useParams<{ id: string }>();
  const router = useRouter();

  const backToProjects = () => {
    router.back();
  };

  return (
    <EnsureAuth>
      <ErrorBoundary fallback={<p>An error occured loading the project.</p>}>
        <Suspense fallback={<Spinner />}>
          <UserProjectDetails projectId={params.id} onBack={backToProjects} />
        </Suspense>
      </ErrorBoundary>
    </EnsureAuth>
  );
}

The error I am encountering is in the UserProjectDetsils component. This component loads data from FireBase and displays it in a UI. The issue I am having is that there seems to be an infinite loop somehow that is repeatedly calling the function to load the data, for some reason. I’ve included the definition of the UderProfileDetails components in the comments.
Answered by Bombay-duck
Found the solution. It turns out React Query isn't playing well with how I am using use(). So, I just need to remove the mutation and just call the async function directly.
View full answer

8 Replies

Bombay-duckOP
Here is the code for the UserProjectDetails component:
export default function UserProjectDetails({
  projectId,
  onBack,
}: UserProjectDetailsProps) {
  const [_, { getProjectById }] = useProjectsContext();

  console.info("Loading project " + projectId);
  const project = use(getProjectById(projectId));
  console.info("Project loaded");

  if (!project) {
    console.info("Project not found");
    return notFound();
  }

  return (
    <section className="overflow-x-auto">
      <UserProjectInfo project={project} onBack={onBack} />
      <Tabs aria-label="Full width tabs" style="fullWidth">
        <Tabs.Item active title="Overview" icon={HiUserCircle}>
          Overview goes here.
        </Tabs.Item>
        <Tabs.Item title="My Betas" icon={HiUserCircle}>
          My Betas go here
        </Tabs.Item>
        <Tabs.Item title="My Surveys" icon={MdDashboard}>
          My Surveys go here.
        </Tabs.Item>
      </Tabs>
    </section>
  );
}
I think the problem may be from my use of React’s [use() hook](https://react.dev/reference/react/use). However, according to the [Suspense Docs](https://react.dev/reference/react/Suspense) I need to use the use() hook to trigger the Suspense component since my getProjectById() returns a promise containing the project details.
Also, the reason I suspect it’s the use() hook that is causing the error is because in my logs, console.info("Loading project " + projectId); is being printed infinite times.
Bombay-duckOP
Bombay-duckOP
Lastly, I don't know if this will help. But, here is the definition of getProjectById() in the ProjectsContext:
const getProjectByIdMutation = useMutation<Project | null, Error, string>({
    throwOnError: true,
    mutationKey: ["get-project-for-id"],
    mutationFn: async (id) => {
      if (user) {
        return await getProjectForId(id, user.id);
      } else {
        throw new UnauthorizedException();
      }
    },
  });

  /**
   * getProjectById()
   *
   * gets a project by its ID.
   * @throws UnauthorizedException when the client is unauthenticated.
   */
  const getProjectById = async (id: string): Promise<Project | null> => {
    return await getProjectByIdMutation.mutateAsync(id);
  };
The getProjectForId() function just makes a call to Firestore to retrieve the project.
export const getProjectForId = async (
  projectId: string,
  userId: string,
  correlation: string = uuid(),
): Promise<Project | null> => {
  try {
    const projectRef = doc(database, CollectionNames.Projects, projectId);
    const record = await getDoc(projectRef);
    let project: Project | null = null;

    if (record.exists()) {
      const data = record.data();

      // ensure the user retrieving the project owns it.
      if (data.owner !== userId) {
        throw new ForbiddenException();
      }

      // convert the record to a project
      project = {
        id: data.id,
        created_on: DateTime.fromISO(data.created_on),
        description: data.description,
        name: data.name,
        owner: data.owner,
      };
    }

    return project;
  } catch (e) {
    if (e instanceof ForbiddenException) {
      throw e;
    } else {
      throw new ServerException();
    }
  }
};
Bombay-duckOP
Bump
Bombay-duckOP
Found the solution. It turns out React Query isn't playing well with how I am using use(). So, I just need to remove the mutation and just call the async function directly.
Answer