How to troubleshoot excessive API calls from the useMember() hook with Memberstack and Next.js?

Post author
Lloyd Li

I’m hitting some issues here wondering if you guys could help

I am using MemberstackProvider from @memberstack/nextjs/client with the following config

<MemberstackProvider config={MEMBERSTACK_CONFIG}>

Comments

7 comments

  • Comment author
    Raquel Lopez

    What url are you using to import Memberstack? It doesn’t look like you’re using the correct one
    https://memberstack.slack.com/archives/C033F0SLTLK/p1734664471530979?thread_ts=1734652878.787199&channel=C033F0SLTLK&message_ts=1734664471.530979

    0
  • Comment author
    Lloyd Li

    Hey Raquel Lopez I am not using the webflow way <script> to import memberstack, but using @memberstack/nextjs/client, so not sure how the solution above could help in my case

    could I also check why they are multiple member request in just one page load? is it whenever I use a useMember() hook, it raise a request?

    0
  • Comment author
    Raquel Lopez

    It’s difficult to diagnose without having to take a better look at your code. I don’t see a cors issue when I accessed at your getstarstruck page. Also there’s not useMember hook at the official documentation, unless you created a custom one. Everytime you invoke memberstack’s getCurrentMember method you’re creating a new request per call

    For the initial issue. If you take a good look at the logs you get to see you’re overloading the server with request and it’s blocking you because there are too many request per amount of time. Try to do one request per page load or one request per action. That way you won’t get the 429 error

    0
  • Comment author
    Lloyd Li

    there is a useMember and useMemberstack provided by @memberstack/nextjs/client

    I didn't create any custom hook

    yes I can see that there is multiple request, but the thing that's confusing is, I am not requesting any thing, other than using the hooks provided. So I need to know behind those hooks, are they initiating a request (which i don't think so?)

    0
  • Comment author
    Raquel Lopez

    I’m currently OOO because of the holiday season. I’m afraid I have resource limited to debug, I only have access to the docs, so I’m comparing the information you sent me from there. You can debug which of the memberstack methods you’re using is creating a request by looking at the package inside code 🤔

    I’m not familiar with the useMember hook, because it’s not on the docs, but you can check if the hook inside has a call to the getCurrentMember method and maybe that’s what’s creating your requests… I believe that’s what causing your 429 errors. What you should do is store the member object in a global state so your app has access to the user object without having to do a request per component.

    useMember does use the getCurrentMember method.  :) and thanks I will
     
    All the nextjs/client methods come from the react package. Check out their docs to follow some of the recommended practices https://developers.memberstack.com/docs/react-package
    0
  • Comment author
    Lloyd Li

    Hey. I don't think that's what is causing the issue and sending request.

    I have created a custom context that wraps useMember() and useMemberstack().

    These 2 hooks went from being called in multiple components to being initialized only once in layout.tsx.

    But I am still getting multiple member request sent.

    Here's the context created.

    'use client';
    
    import { Member } from '@/types/Member';
    import { SellerData } from '@/types/api/Seller';
    import React, { createContext, useContext } from 'react';
    import { UpdateMemberAuthPayload, UpdateMemberPayload, GetMemberJSONPayload } from '@memberstack/dom';
    import { useMember, useMemberstack } from '@memberstack/nextjs/client';
    
    interface MemberstackContextType {
      member: Member | null;
      company: SellerData | null;
      memberJSON: {
        jsonData?: {
          json: object;
        };
      } | null;
      // member hook methods
      updateEmail: (email: string) => Promise<UpdateMemberAuthPayload>;
      updatePassword: (oldPassword: string, newPassword: string) => Promise<UpdateMemberAuthPayload>;
      updateCustomFields: (customFields: any) => Promise<UpdateMemberPayload>;
      updateMemberJSON: (json: object) => Promise<GetMemberJSONPayload>;
      // memberstack instance methods
      memberstack: ReturnType<typeof useMemberstack>;
    }
    
    interface ProviderProps {
      children: React.ReactNode;
      member: Member | null;
      company: SellerData | null;
    }
    
    const MemberstackContext = createContext<MemberstackContextType | undefined>(undefined);
    
    export function SSRMemberstackProvider({ children, member, company }: ProviderProps) {
      const memberHook = useMember();
      const memberstack = useMemberstack();
    
      const contextValue: MemberstackContextType = {
        member,
        company,
        memberJSON: memberHook?.memberJSON || null,
        // member hook methods
        updateEmail: memberHook?.updateEmail || (async () => ({}) as UpdateMemberAuthPayload),
        updatePassword: memberHook?.updatePassword || (async () => ({}) as UpdateMemberAuthPayload),
        updateCustomFields: memberHook?.updateCustomFields || (async () => ({}) as UpdateMemberPayload),
        updateMemberJSON: memberHook?.updateMemberJSON || (async () => ({}) as GetMemberJSONPayload),
        // memberstack instance
        memberstack,
      };
    
      return <MemberstackContext.Provider value={contextValue}>{children}</MemberstackContext.Provider>;
    }
    
    export function useLoggedInUser() {
      const context = useContext(MemberstackContext);
    
      if (!context) {
        throw new Error('useLoggedInUser must be used within a SSRMemberstackProvider');
      }
    
      return context;
    }
    

    A example of using this context is

    const { member, updateCustomFields, memberstack } = useLoggedInUser();
    

    Initializing this context in layout.tsx:

            <MemberstackProvider config={MEMBERSTACK_CONFIG}>
              <SSRMemberstackProvider member={member} company={company}>
    

    The member and company object in this context came from a server side request of member object

    export async function fetchMemberData(token?: string): Promise<{ data: Member | null }> {
      if (!token) token = getAuthToken();
    
      const response = await fetch(`${CLIENT_API_ENDPOINT}/member`, {
        cache: 'no-store',
        headers: {
          Authorization: `Bearer ${token}`,
          ['X-API-KEY']: MEMBERSTACK_PUBLIC_KEY || '',
        },
      });
    
      if (!response.ok) {
        throw new Error('Failed to fetch member data');
      }
    
      return response.json();
    }

    0
  • Comment author
    Raquel Lopez

    I had to rely on chatGPT's help for explanation, but in summary its an implementation issue.if each component calls useLoggedInUser, the underlying useMember() method will indeed be invoked separately for each component. This is because useMember() is called inside the SSRMemberstackProvider and contributes to the contextValue. Each component accessing the context indirectly depends on useMember() being invoked during the rendering of the provider.
    Why Does This Happen?

    1. React Context and State Updates:
      • SSRMemberstackProvider creates a contextValue that includes the result of useMember().
      • Each time a component accesses the context via useLoggedInUser, it effectively interacts with the latest contextValue.
      • If useMember() internally triggers an operation (like fetching data), it will run every time the provider re-renders.
    2. Multiple Components Using useLoggedInUser:
      • Each call to useLoggedInUser by separate components does not share a cached result of useMember(); instead, they all rely on the contextValue that may trigger multiple evaluations if the SSRMemberstackProvider re-renders.
    3. Provider's useMember Behavior:
      • If useMember is not designed to cache data (e.g., using useState or useMemo inside the SSRMemberstackProvider), it will recompute its results or make requests each time the provider is rendered.
        The nextJS package is a combination of the DOMpackage and the react package. So I recommended you to use a method of the react package but applied to the next package to send the member in your provider. Or you can create the custom hooks yourself by using the DOM package alone.
    0

Please sign in to leave a comment.