简体   繁体   中英

How to handle multiple error response in React?

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;

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM