1

Okay so I am using Redux and Axios to post data to my server and subsequently rendering the server response, error or otherwise, in my component. There are multiple post requests' response that fill up the Redux store and I am trying to render those responses whenever one is triggered.

I am getting the response from the server in my component like this:

const createdPost = useSelector( state => state.createPost );
const { loading: createdPostLoading, error: createdPostError, success: createdPostSuccess } = createdPost;

const uploadedImage = useSelector( state => state.uploadImage );
const { loading: uploadedImageLoading, error: uploadedImageError, success: uploadedImageSuccess } = uploadedImage;

const deletedImage = useSelector( state => state.deleteImage);
const { loading: deletedImageLoading, error: deletedImageError, success: deletedImageSuccess } = deletedImage;

So in my useEffect I'm checking their values and rendering them, like this:

const [ responseMessage, setResponseMessage ] = useState( '' );

useEffect( () => {

         if ( createdPostError ) {
            setResponseMessage( createdPostError );
        } else if ( createdPostSuccess ) {
            setResponseMessage( createdPostSuccess );
        } else if ( uploadedImageError ) {
            setResponseMessage( uploadedImageError );
        } else if ( uploadedImageSuccess ) {
            setResponseMessage( uploadedImageSuccess );
        } else if ( deletedImageError ) {
            setResponseMessage( deletedImageError );
        } else if ( deletedImageSuccess ) {
            setResponseMessage( deletedImageSuccess );
        }

}, [ createdPostError, createdPostSuccess, uploadedImageError, uploadedImageSuccess, deletedImageError, deletedImageSuccess ] );

And the render function look like this:

{
     <Message type='Error' text={responseMessage} />
}

The issue right now is whenever I try to delete an image and the server fails to delete it, I get the uploadedImageSuccess response, which I think I'm getting from the store where it is already populated with previously uploaded image response from the server. I am supposed to get the delete image response. If I log the value of deletedImageError then I can see the actual server response. It doesn't render it.

The conditional statement in useEffect for the uploadedImageSuccesss is being triggered. So I am guessing this is not the proper way of handling error. Anybody know a good way of handling them? Where am I going wrong here?

UPDATE

Here's the full code:

Redux:

=================
CONSTANTS.js:
=================

export const CREATE_POST_REQUEST = 'CREATE_POST_REQUEST';
export const CREATE_POST_SUCCESS = 'CREATE_POST_SUCCESS';
export const CREATE_POST_FAIL    = 'CREATE_POST_FAIL';

export const UPLOAD_IMAGE_REQUEST = 'UPLOAD_IMAGE_REQUEST';
export const UPLOAD_IMAGE_SUCCESS = 'UPLOAD_IMAGE_SUCCESS';
export const UPLOAD_IMAGE_FAIL    = 'UPLOAD_IMAGE_FAIL';

export const DELETE_IMAGE_REQUEST = 'DELETE_IMAGE_REQUEST';
export const DELETE_IMAGE_SUCCESS = 'DELETE_IMAGE_SUCCESS';
export const DELETE_IMAGE_FAIL    = 'DELETE_IMAGE_FAIL'; 

=================
REDUCERjs
=================

export const createPostReducer = ( state = { campaign: {} }, action ) => {

    switch ( action.type ) {
        case CREATE_POST_REQUEST:
            return { loading: true };
        case CREATE_POST_SUCCESS:
            return {
                loading: false,
                success: action.payload
            };
        case CREATE_POST_FAIL:
            return {
                loading: false,
                error: action.payload
            };
        default:
            return state;
    }

}

export const uploadImageReducer = ( state = {}, action ) => {

    switch ( action.type ) {
        case UPLOAD_IMAGE_REQUEST:
            return { loading: true };
        case UPLOAD_IMAGE_SUCCESS:
            return {
                loading: false,
                success: action.payload
            };
        case UPLOAD_IMAGE_FAIL:
            return {
                loading: false,
                error: action.payload
            };
        default:
            return state;
    }

}

export const deleteImageReducer = ( state = {}, action ) => {

    switch ( action.type ) {
        case DELETE_IMAGE_REQUEST:
            return { loading: true };
        case DELETE_IMAGE_SUCCESS:
            return {
                loading: false,
                success: action.payload
            };
        case DELETE_IMAGE_FAIL:
            return {
                loading: false,
                error: action.payload
            };
        default:
            return state;
    }

}

=================
ACTIONS.js
=================

export const createPost = ( postData ) => async ( dispatch ) => {
    
    try {

        dispatch({
            type: CREATE_POST_REQUEST
        });


        const { data } = await axios.post( '/api/posts', postData);

        dispatch({
            type: CREATE_POST_SUCCESS,
            payload: data.message
        });

    } catch ( error ) {

        dispatch({ 
            type: CREATE_POST_FAIL,
            payload: error.message
        });
        
    }

}

export const uploadImage = ( imageData ) => async ( dispatch ) => {
    
    try {

        dispatch({
            type: UPLOAD_IMAGE_REQUEST
        });

        const { data } = await axios.post( '/api/posts/upload-image', imageData );

        dispatch({
            type: UPLOAD_IMAGE_SUCCESS,
            payload: data
        });

    } catch ( error ) {

        dispatch({ 
            type: UPLOAD_IMAGE_FAIL,
            payload: error.message
        });
        
    }

}

export const deleteImage = ( imageData ) => async ( dispatch ) => {
    
    try {

        dispatch({
            type: DELETE_IMAGE_REQUEST
        });

        const { data } = await axios.post( '/api/posts/delete-image', imageData );

        dispatch({
            type: DELETE_IMAGE_SUCCESS,
            payload: data
        });

    } catch ( error ) {

        dispatch({ 
            type: DELETE_IMAGE_FAIL,
            payload: error.message
        });
        
    }

}

=================
STORE.js
=================

const reducer = combineReducers({
    createPost: createPostReducer,
    uploadImage: uploadImageReducer,
    deleteImage: deleteImageReducer
});

const middleware = [ thunk ];

const store = createStore( 
    reducer, 
    initialState, 
    composeWithDevTools( applyMiddleware( ...middleware ) ) 
);

export default store;

Here's how the component looks like:

const Post = () => {

        const [ responseMessage, setResponseMessage ] = useState( '' );

        const createdPost = useSelector( state => state.createPost );
        const { loading: createdPostLoading, error: createdPostError, success: createdPostSuccess } = createdPost;

         const uploadedImage = useSelector( state => state.uploadImage );
         const { loading: uploadedImageLoading, error: uploadedImageError, success: uploadedImageSuccess } = uploadedImage;

         const deletedImage = useSelector( state => state.deleteImage);
         const { loading: deletedImageLoading, error: deletedImageError, success: deletedImageSuccess } = deletedImage;

        useEffect( () => {

              if ( createdPostError ) {
                    setResponseMessage( createdPostError );
               } else if ( createdPostSuccess ) {
                    setResponseMessage( createdPostSuccess );
               } else if ( uploadedImageError ) {
                    setResponseMessage( uploadedImageError );
               } else if ( uploadedImageSuccess ) {
                    setResponseMessage( uploadedImageSuccess );
               } else if ( deletedImageError ) {
                    setResponseMessage( deletedImageError );
               } else if ( deletedImageSuccess ) {
                    setResponseMessage( deletedImageSuccess );
               }

         }, [ createdPostError, createdPostSuccess, uploadedImageError, uploadedImageSuccess, deletedImageError, deletedImageSuccess ] );


    return (

         {
             <Message type='Error' text={responseMessage} />
         }
    )
}

export default Post;
7
  • 1
    not enough detail to tell you the answer. Can you please share your code codesandbox etc or add a screenshot of the reducer, action, store and API call Commented Jan 23, 2022 at 17:34
  • @MuhammadBilalBangash please wait. I'm updating the post with the code. Commented Jan 23, 2022 at 17:34
  • @MuhammadBilalBangash check now. I have posted everything. Commented Jan 23, 2022 at 17:47
  • ok let me check it Commented Jan 23, 2022 at 17:48
  • can you please share code on codesandbox so I can run it?? Commented Jan 23, 2022 at 17:56

1 Answer 1

1

Create separate Reducer for Generic Error Handler

export const genericErrorReducer=(state,action){
 switch(action.type){
    case 'GENERIC_ERROR':
    return {
      error:action.payload
    }
 }
}

call this when you are getting error from server rather then creating separate local state for each error

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.