I have an unregistered user that works with my application, getting some progress. I keep this progress in local storage. Then, when the user decides to register, I send a PUT request to sync his progress with DB.
For that I track its status
and when it’s become authenticated
and the progress
parameter empty, I send a PUT request, but the problem is it sends dozens of PUT requests to update the progress instead of one.
'use client'
import { useSession, signIn, signOut, useUser } from 'next-auth/react'
import { use, useContext, useEffect, useState } from 'react'
import AppContext from '../../utils/AppContext'
const updateProfile = async (email, prog) => {
await fetch(`http://localhost:3000/api/users/${email}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
progress: prog,
}),
})
}
export default function Component() {
const { progressArr, setProgressArr } = useContext(AppContext)
const { data: session, status } = useSession()
function updateUser() {
use(updateProfile(session.user.email, progressArr))
}
if (status === 'authenticated') {
if (!session.user.progress) {
updateUser()
}
}
if (session) {
return (
<>
Signed in as {session.user.email} <br />
<button onClick={() => signOut()}>Sign out</button>
</>
)
}
return (
<>
Not signed in <br />
<button onClick={() => signIn()}>Sign in</button>
</>
)
}
P.S. If it should be done in another way, share your ideas with me please.
5
Answers
Your
updateUser
is called on "component render" so every time when your application changes state or any of parent components change stateupdateUser
gets called.Since this code introduces a side-effect for your component you can try to put this code into
useEffect
hook like:However I won’t recommend to keep components responsible for maintaining application state and handling side effects.
My recommendation would be to onboard you app with app-state management framework, like redux and move your data submission logic to middleware.
This way your data flow would look like:
It seems to me that
updateUser()
is getting called multiple times by accident.You could try to keep track of your request by adding something like
updateInProgress
as a state and set it totrue
onceupdateUser()
is triggered and set it tofalse
afterwards again.After you’ve done this, you could just return if there is already an update in progress:
That could be the cause of multiple render cycles. Moving logic to
useEffect
might beThere is useEffect hook to send a single request to update the progress of the user. useEffect hook is called when the session, status, or progressArr changes. If the user is authenticated and their progress is undefined, we call the updateProfile
Try this code. I think it will help you
Can you please try below code:
using the
useEffect
hook to run theupdateUser()
by adding[progressArr]
as the second argument touseEffect
.Note:
In theory
useContext
anduseSession
hooks to render sepcific contents (data) depending on authenticated user. It nice to implementing over authentication flow.useEffect
hook is used to update the user’s profile with theprogressArr
data if the user is authenticated and does not have a progress field in their profile. The updateProfile function is likely used to make an API call to update the user’s profile.