0

I'm currently working on my first NextJS app after a long hiatus. The first thing I'm working on is a small app that's powered by Firebase.

After reading some documentation on Context and then Firebase's onAuthStateChanged(), I made this component to serve as a way to distribute user login status (or lack thereof) to my entire app:

'use client'

import { onAuthStateChanged } from 'firebase/auth'
import { createContext, useState, useEffect, ReactNode } from 'react'
import { fbAuth } from '../firebase/firebase'

const SessionContext = createContext({ user: {} })

const SessionProvider = ({ children }: { children: ReactNode }) => {
  // This should handle current state of who is logged in.
  const [currentUser, setUser] = useState({ user: {} })

  useEffect(() => {
    onAuthStateChanged(fbAuth, (user) => {
      console.log('state changed')
      if (user) {
        setUser({ user })
      } else {
        setUser({ user: {} })
      }
    })
  })

  return <SessionContext value={currentUser}>{children}</SessionContext>
}

export default SessionProvider

This seems like it should work fine, the only issue being that it's a Client Component and requires a "use client" at the top obviously due to use of useState, which is perfectly fine.

The issue comes when I create a small login form in the app that's wrapped with this Context.

I have this example component serving as a basic login form at the moment:

'use client'

import { useActionState } from 'react'
import { barlow } from '../util'

export default function Login() {
  const [state, formAction] = useActionState(async (_, formData: FormData) => {
    console.log(formData.get('email'))
    console.log(formData.get('password'))
  }, null)

  return (
    <div className="card w-3xl rounded-xl border border-neutral-700 bg-base-300 p-4">
      <span className={`${barlow.className} text-3xl text-center mb-6`}>Login</span>
      <form action={formAction}>
        <span className="text-sm text-left mb-1">Login:</span>
        <input type="email" autoComplete="email" name="email" className="input mb-4 w-full" />
        <span className="text-sm text-left mb-1">Password:</span>
        <input type="password" autoComplete="password" name="password" className="input mb-4 w-full" />
        <div className="grid grid-cols-2 gap-4">
          <button className="btn btn-block btn-primary">Login</button>
          <button className="btn btn-block btn-primary">Reset</button>
        </div>
      </form>
    </div>
  )
}

However, when I submit the form, it seems that an infinite loop is being triggered and the tab just sort of freezes until I kill it manually and reload the page.

Am I overlooking something in the handler itself? What's causing the infinite re-rendering of stuff? I'm not even logging -in- to anything, just trying to grab the values to get used to the concept of proper form handling using the new APIs.

Thanks in advance! I'm -very- confused and feel like I must be making a simple mistake.

1 Answer 1

1

It turns out that my problem was indeed an oversight!

When I declared the instance of useEffect meant to watch for Firebase login status, I forgot to include the dependency array, which...results in an infinite loop!

It should be this (after fixing it):

useEffect(() => {
    onAuthStateChanged(fbAuth, (user) => {
      console.log('state changed')
      if (user) {
        setUser({ user })
      } else {
        setUser({ user: {} })
      }
    })
  }, [])   // Dependency array goes here!   Oops!
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.