Reputation: 555
I'm working on a React application with Django Rest Framework where I'm updating user profile. Everything works fine but there's one tiny problem I can't figure out the solution of. When I update user email and email entered already exists in DB, DRF sends back an error. In my user reducer, state is updated with the error. But react doesn't render that output, it renders the success scenario, although email is not updated.
When I sumbit the form second time with the same email, it renders the error message. Now if I change the email to a unique one and submit, email is updated in DB and so does the updateProfileState. But the error message is rendered on the frontend profile page. Again, if I submit the form with same email address or any other existing email, success scenario is rendered.I have to submit the form once again to get the error message rendered on screen.
Naïve description of this issue would be, my frontend page is one state behind the actual state.
Here is my action
export const updateUserProfile = (user)=> async (dispatch, getState) =>{ const {userLogin: {userInfo}} = getState()
try {
dispatch({
type: USER_PROFILE_UPDATE_REQUEST
})
const config = {
headers : {
'Content-Type':'application/json',
Authorization: `Bearer ${userInfo.access}`
}
}
const {data} = await axios.patch('/api/v1/users/me/', user, config)
dispatch({
type: USER_PROFILE_UPDATE_SUCCESS,
payload: data
})
}
catch (error) {
dispatch({
type: USER_PROFILE_UPDATE_FAIL,
payload: error.response.data.old_password ? error.response.data.old_password
: error.response.data
})
}
}
and my reducer function
export const userUpdateProfileReducer=(state={}, action)=> {
switch (action.type) {
case USER_PROFILE_UPDATE_REQUEST:
return {...state, success: false}
case USER_PROFILE_UPDATE_SUCCESS:
return {success: true, user : action.payload}
case USER_PROFILE_UPDATE_FAIL:
return {success: false, error: action.payload}
default:
return state
}
}
my handleSubmit function
const handleSubmit = event => {
event.preventDefault();
if (Object.values(formValidity).every(Boolean)) {
dispatch(updateUserProfile({'first_name': formValues.first_name, 'last_name':formValues.last_name, 'username': formValues.email, 'email': formValues.email}))
if(success===true) {
console.log(success)
toast('Profile updated successfully...', {position:toast.POSITION.TOP_CENTER, autoClose: 2000})
}
else {
error && error["email"].map(msg => (formErrors.email = msg))
}
}
};
Success and error variables are being extracted from reducern usig useSelector.
const updateProfile = useSelector(state => state.userUpdateProfile)
const {loading, success, error} = updateProfile
When I check the state in Redux Dev Tools, state is being updated correctly. Only my front page doesn't get the right value. And this happens only when I update email. For anything other than email, it works fine.
Can anybody please help me out what am I doing wrong? Edit: Here is the form I want to render the error message. In case of success scenario, I'm displaying a toast popup. (See in handleSubmit function)
<FormGroup className="row">
<FormLabel className="col-xl-3 col-lg-3 col-form-label text-alert">Email</FormLabel>
<div className="col-lg-9 col-xl-6">
<FormControl
type="email"
name="email"
className={`form-control form-control-lg form-control-solid mb-2 ${
formErrors.email ? "is-invalid" : ""
}`}
placeholder="Enter Email"
onChange={handleChange}
value={formValues.email}
/>
<div className="ml-2 text-md-left invalid-feedback">{formErrors.email}</div>
</div>
</FormGroup>
Upvotes: 0
Views: 100
Reputation: 24
if(success===true) {
console.log(success)
toast('Profile updated successfully...', {position:toast.POSITION.TOP_CENTER, autoClose: 2000})
}
else {
error && error["email"].map(msg => (formErrors.email = msg))
}
This runs just after the dispatch statement. So the values this gets is not updated as the dispatch takes some time to update the state as it is a network request.
Try using await, or do the checking in a useEffect(page-level checking for any errors in page )
useEffect(() => {
if (props.error) {
toast.error(props.error);
}
if(props.success){
toast.success('success message')
}
}, [props.error, props.success]);
Upvotes: 1