skip to Main Content

here is the code:

import { type AppType } from 'next/app'
import { api } from '~/utils/api'
import '~/styles/globals.css'
import Nav from '~/components/Nav'
import { useEffect, useState } from 'react'

const MyApp: AppType = ({ Component, pageProps }) => {
  const [showCart, setShowCart] = useState(false)
  const [loading, setLoading] = useState(false)

  const createSession = api.user.createSession.useMutation()

  const generateId = async (): Promise<string | undefined> => {
    const res = await createSession.mutateAsync()
    if (res.response) {
      return res.response.id
    } else if (res.error) {
      return res.error
    }
  }

  const setSessionId = async () => {
    const tmp: string | undefined = await generateId()
    if (tmp) document.cookie = `sessionId=${tmp}`
    setLoading(false)
  }

  useEffect(() => {
    if (!loading) {
      setLoading(true)
      const cookieString: string = document.cookie

      const cookies: string[] = cookieString.split(';') || []

      let sessionId: string | null = null

      for (let i = 0; i < cookies.length; i++) {
        const cookie: string | undefined = cookies[i]

        if (!cookie || cookie.trim() === '') {
          continue
        }

        if (cookie.trim().startsWith('sessionId=')) {
          sessionId = cookie.trim().substring('sessionId='.length)
          break
        }
      }
      if (!sessionId) {
        void setSessionId()
      }
    }
  }, [])

  return (
    <>
      <Nav showCart={showCart} setShowCart={setShowCart} />
      <h1>{loading && 'LOADING'}</h1>
      <Component {...pageProps} />
    </>
  )
}

export default api.withTRPC(MyApp)

I am using trpc and prisma. for some reason the useEffect is running twice and it is posting to the db twice. any idea what’s causing the re-render? the loading is always false for some reason even after I set it to true. is it because I am setting it wrong?
I initially thought that maybe it was rendering twice, once in the server and once in the client. but I logged the window object and they were both defined.

any idea what I am doing wrong?

2

Answers


  1. I think this wokr once setLoadin to true , and update useEffect

    import { type AppType } from 'next/app';
    import { api } from '~/utils/api';
    import '~/styles/globals.css';
    import Nav from '~/components/Nav';
    import { useEffect, useState } from 'react';
    
    const MyApp: AppType = ({ Component, pageProps }) => {
      const [showCart, setShowCart] = useState(false);
      const [loading, setLoading] = useState(true); // Set initial loading state to true
    
      const createSession = api.user.createSession.useMutation();
    
      const generateId = async (): Promise<string | undefined> => {
        const res = await createSession.mutateAsync();
        if (res.response) {
          return res.response.id;
        } else if (res.error) {
          return res.error;
        }
      };
    
      const setSessionId = async () => {
        const tmp: string | undefined = await generateId();
        if (tmp) document.cookie = `sessionId=${tmp}`;
        setLoading(false);
      };
    
      useEffect(() => {
        const getSessionId = () => {
          const cookieString: string = document.cookie;
          const cookies: string[] = cookieString.split(';') || [];
    
          let sessionId: string | null = null;
    
          for (let i = 0; i < cookies.length; i++) {
            const cookie: string | undefined = cookies[i];
    
            if (!cookie || cookie.trim() === '') {
              continue;
            }
    
            if (cookie.trim().startsWith('sessionId=')) {
              sessionId = cookie.trim().substring('sessionId='.length);
              break;
            }
          }
    
          return sessionId;
        };
    
        if (!getSessionId()) {
          setSessionId();
        } else {
          setLoading(false); // Set loading to false  present
        }
      }, []);
    
      return (
        <>
          <Nav showCart={showCart} setShowCart={setShowCart} />
          {loading && <h1>LOADING</h1>} {/* Show LOADING only if loading is true */}
          <Component {...pageProps} />
        </>
      );
    };
    
    export default api.withTRPC(MyApp);
    
    Login or Signup to reply.
  2. The issue you’re experiencing with useEffect running twice and posting to the database twice could be related to the Next.js server-side rendering (SSR) behavior. When using Next.js, the initial rendering occurs on the server and then the component rehydrates on the client side.

    To address this, you can add a condition in your useEffect to only execute the code on the client side. You can do this by checking if typeof window is defined, as the window object is only available in the browser environment.

    Here’s an updated version of your code with the modification:

        // ...
    
    useEffect(() => {
      if (typeof window !== 'undefined' && !loading) {
        setLoading(true);
        const cookieString = document.cookie;
        // Rest of your code...
      }
    }, []);
    
    // ...
    
    

    By adding typeof window !== ‘undefined’ as a condition, the code inside the useEffect will only run on the client side and prevent it from executing on the server side during the initial render. This should help eliminate the duplicated database posts.

    Regarding the issue with loading always being false, it could be because setLoading(true) is asynchronous, and the subsequent line if (!loading) may not reflect the updated value immediately. If you need to check the value of loading, you can add a console.log statement after setLoading(true) to see if it changes accordingly.

    Make sure to test your code with this modification and verify if the behavior is as expected.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search