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 on doing so in my scenario?
Thank you!
There are of course others ways of doing this, but the one that wouldn't change that much your current structure is to change onSubmit
function so you dont do the redirection there:
const onSubmit = async (credentials) => {
setLoading(true)
await login(credentials)
resetForm({})
setLoading(false)
}
Create an useEffect
that would the do the redirection, but based on wether 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.
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 login 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
.