Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditionally check value from context and then navigate after login in the same function call in React

In React, I'm using the context API to set the user data or the errors returned by the API request:

// context
const [currentUser, setCurrentUser] = useState("")
const [error, setError] = useState("")

async function login(credentials) {
    setError("")
    try {
        ...API request
        const data = await response.json()
        if(data.success) {
            setCurrentUser(data)
        } else {
            setError(data.error)
        }
    } catch (error) {
        setError("Something went wrong. Please try again.")
    }
}

<AuthContext.Provider value={login, currentUser, error}>
    {children}
</AuthContext.Provider>

Then in my component:

//component
const { login, currentUser, error } = useContext(AuthContext)

const onSubmit = async (credentials) => {
    setLoading(true)
    await login(credentials)
    resetForm({})
    setLoading(false)
    !error && navigate("/")
}

return (
    ...
)

Now the onSubmit function allows the user to navigate to / even if there is an error set by the context - this is because (I think) the error is still null by the time it's checked and the component doesn't get the chance to rerender to get the newest value.

What would be the best approach to avoid this behavior? Should I handle the error locally in the component and not the context? If yes, what would be the best way to do so in my scenario?

like image 672
labilouser Avatar asked Jan 18 '26 07:01

labilouser


1 Answers

Quick solution

Of course, there are other ways of doing this, but the one that wouldn't change your current structure much is to change the onSubmit function so you don't do the redirection there:

const onSubmit = async (credentials) => {
    setLoading(true)
    await login(credentials)
    resetForm({})
    setLoading(false)
}

Create an useEffect that would do the redirection, but based on whether there is a user or not:

useEffect(()=>{
  if(currentUser){
    navigate("/")
  }
},[currentUser])

And yes, when you are calling !error && navigate("/"), there is no re-render yet, and therefore error is still equal to "", which is why the redirection is happening right away.

Another way

Assuming that the login process is handled in one place (which is the case in most scenarios), there is no need to have login function and error state as part of the context. The context should export just setCurrentUser and currentUser.

<AuthContext.Provider value={currentUser, setCurrentUser}>
    {children}
</AuthContext.Provider>

The login and errors related to logging would be handled inside the login page, and it would call setCurrentUser to update the context for other components:

const {currentUser, setCurrentUser} =  useContext(AuthContext)

And you would use the same useEffect as above to make redirection when there is currentUser.

like image 114
yousoumar Avatar answered Jan 20 '26 20:01

yousoumar