Toseef_Ahmed
Toseef_Ahmed

Reputation: 555

ReactJS states not being rendered correctly

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

Answers (1)

rohit
rohit

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

Related Questions