T
TanStack•14mo ago
correct-apricot

Race condition with beforeLoad and routerContext

I have a function that does the following in a mutation:
const mutation = useMutation({
mutationFn: (signUpFormData) => {
return signUp(signUpFormData)
},
onSuccess: (data) => {
if (data.access_token) {
login(data.access_token)
setTimeout(() => {
navigate({ to: '/user' })
}, 1000)
}
},
onError: (error) => {
console.error('Sign up failed: ', error.message)
// TODO: Show an error message to the user here
setErrorMessage(error.message)
},
})
const mutation = useMutation({
mutationFn: (signUpFormData) => {
return signUp(signUpFormData)
},
onSuccess: (data) => {
if (data.access_token) {
login(data.access_token)
setTimeout(() => {
navigate({ to: '/user' })
}, 1000)
}
},
onError: (error) => {
console.error('Sign up failed: ', error.message)
// TODO: Show an error message to the user here
setErrorMessage(error.message)
},
})
If I remove the setTimeout, I get a null value for token in my beforeLoad of /user.
export const Route = createFileRoute('/user/')({
beforeLoad: ({ context, location }) => {
const token = context.auth.token

if (!token) {
throw redirect({
to: '/sign-in',
search: {
redirect: location.href,
},
})
}
},
component: () => <User />,
})
export const Route = createFileRoute('/user/')({
beforeLoad: ({ context, location }) => {
const token = context.auth.token

if (!token) {
throw redirect({
to: '/sign-in',
search: {
redirect: location.href,
},
})
}
},
component: () => <User />,
})
How can I avoid this race condition?
3 Replies
correct-apricot
correct-apricotOP•14mo ago
Think this may be answered in the Routing with async data post below, will give the useEffect trick a shot yea thats a bit different, the login function on mine should be synchronous and thus finish + update context before calling navigate but navigate fires before the context resets this is probably some basic React problem 🤔 yep, simple react problem with context and state.
const { login, error, token } = useAuth()
const [errorMessage, setErrorMessage] = useState('')
const navigate = useNavigate()

useEffect(() => {
if (token) {
navigate({ to: '/user' })
}
}, [token, navigate])

const form = useForm({
...formOpts,
onSubmit: async ({ value }) => {
mutation.mutate({ ...value })
},
})

// TODO: Account for API errors
const mutation = useMutation({
mutationFn: (signUpFormData) => {
return signUp(signUpFormData)
},
onSuccess: (data) => {
if (data.access_token) {
login(data.access_token)
}
},
onError: (error) => {
console.error('Sign up failed: ', error.message)
// TODO: Show an error message to the user here
setErrorMessage(error.message)
},
})
const { login, error, token } = useAuth()
const [errorMessage, setErrorMessage] = useState('')
const navigate = useNavigate()

useEffect(() => {
if (token) {
navigate({ to: '/user' })
}
}, [token, navigate])

const form = useForm({
...formOpts,
onSubmit: async ({ value }) => {
mutation.mutate({ ...value })
},
})

// TODO: Account for API errors
const mutation = useMutation({
mutationFn: (signUpFormData) => {
return signUp(signUpFormData)
},
onSuccess: (data) => {
if (data.access_token) {
login(data.access_token)
}
},
onError: (error) => {
console.error('Sign up failed: ', error.message)
// TODO: Show an error message to the user here
setErrorMessage(error.message)
},
})
onSettled also works here in the mutation
fascinating-indigo
fascinating-indigo•14mo ago
I had the same issue maybe I would try a useEffect
jolly-crimson
jolly-crimson•14mo ago
i throw a promise, and wrap my applicaiton in suspense, until authentication has been loaded :))

Did you find this page helpful?