Hi guys,
I noticed that after I signup or create new user I need to either refresh the page or wait a few seconds before I try to do any api calls like posts requests or put requests. I would appreciate any help. It’s like it doesn’t immediately recognize the token in localstorage. I am using the MERN stack and Redux.
Signup Page
const Signup = () => {
const { register, handleSubmit, formState: { errors } } = useForm({
defaultValues: {
username: "",
email: "",
password: "",
bio: ""
}
});
const navigate = useNavigate()
const dispatch = useDispatch()
const newUser = async (data) => {
try {
await dispatch(registerUser(data)).unwrap()
toast.success('New Account Created')
navigate('/feed')
} catch (error) {
toast.error(error)
}
}
return (
<Box
display="flex"
alignItems="center"
justifyContent="center"
className="signupWrapper"
sx={{
p: 7
}}
>
<Grid
width={700}
container
className="signupContainer"
direction="column"
justifyContent="center"
alignItems="center"
sx={{
p: 5,
boxShadow: 2,
borderRadius: 2,
'& button': { my: 3 },
}}
>
<AccountCircleIcon sx={{ fontSize: 80 }} />
<h2 className='loginTitle'>Signup</h2>
<Stack>
{errors.username && <Alert severity="error"><AlertTitle>Error</AlertTitle><span>Username must be 5 characters long</span></Alert>}
{errors.email && <Alert severity="error"><AlertTitle>Error</AlertTitle><span>Please enter a valid email</span></Alert>}
{errors.password && <Alert severity="error"><AlertTitle>Error</AlertTitle><span>A password must contain at least 8 Characters, 1 Uppercase Character, 1 lowercase character, 1 Number, and 1 Special Character</span></Alert>}
{errors.bio && <Alert severity="error"><AlertTitle>Error</AlertTitle><span>A short bio is required.</span></Alert>}
</Stack>
<form className="registerForm" onSubmit={handleSubmit(newUser)}>
<TextField
id="username"
name="username"
label="Username"
placeholder="Username"
{...register("username", { required: true, minLength: 5 })}
variant="filled"
fullWidth
margin="normal"
/>
<TextField
id="email"
name="email"
label="Email"
placeholder="email"
{...register("email",
{
required: true,
validate: {
matchPattern: (value) =>
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
value
)
}
})}
variant="filled"
fullWidth
margin="normal"
/>
<TextField
id="password"
name="password"
label="Password"
placeholder="Password"
{...register("password", {
required: true,
validate: {
checkLength: (value) => value.length >= 8,
matchPattern: (value) =>
/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s)(?=.*[!@#$*])/.test(
value
)
}
})}
variant="filled"
fullWidth
margin="normal"
/>
<TextField
className="bioContainer"
name="bio"
label="User Bio"
placeholder="Write Bio"
fullWidth
multiline
margin="normal"
{...register("bio", { required: true, minLength: 10 })}
/>
<button className="signupBtn" type="submit">Submit</button>
</form>
<div>
<Link to={"/login"} className='loginLink'>
Have an account? Login Now
</Link>
</div>
</Grid>
</Box>
)
}
API
router.post("/signup", [
check("username", "Please enter a username at least 5 characters long")
.not()
.bail()
.isEmpty()
.bail()
.isLength({ min: 5 })
.bail()
.trim()
.custom(value => {
return UserService.find({
username: value
}).then(user => {
if (user) {
return res.status(400).send({ error: 'Username already being used' })
}
});
}).bail(),
check("email", "Please enter a valid email")
.not()
.bail()
.isEmpty()
.bail()
.isEmail()
.bail()
.normalizeEmail()
.bail()
.trim()
.custom(value => {
return UserService.find({
email: value
}).then(user => {
if (user) {
return res.status(400).send({ error: 'Email is already being used' })
}
});
}).bail(),
check("password", "A password must contain at least 8 Characters, 1 Uppercase Character, 1 lowercase character, 1 Number, and 1 Special Character")
.not()
.bail()
.isEmpty()
.bail()
.isStrongPassword()
.bail()
.trim(),
check("bio", "Please enter a short bio")
.not()
.bail()
.isEmpty()
.bail()
.trim(),
], (req, res, next) => {
const errors = validationResult(req)
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() })
} else {
bcrypt.hash(req.body.password.trim(), 10, (err, hashedPassword) => {
let newUser = {
username: req.body.username.trim(),
email: req.body.email.trim(),
password: hashedPassword,
bio: req.body.bio
}
UserService.create(newUser)
.then((user) => {
const token = createToken(user._id)
let currentUser = {
id: user._id,
username: req.body.username.trim(),
email: req.body.email.trim(),
bio: req.body.bio
}
res.status(200).json({ currentUser, token })
}).catch((err) => {
res.status(404)
res.end()
})
})
}
});
authSlice
export const registerUser = createAsyncThunk(‘auth/signup’, async (user, thunkAPI) => {
try {
return await authService.register(user)
} catch (error) {
const message = “Unable to register user”
console.log(error);
return thunkAPI.rejectWithValue(message)
}
})
authservice
// Register User
const register = async (userData) => {
const response = await axios.post(`${API_URL}/api/auth/signup`, userData)
if (response.data) {
localStorage.setItem('user', JSON.stringify(response.data))
}
return response.data
}