5
votes

I have an async thunk that fetches some information from a web service, it can dispatch three types of actions

FETCH_REQUESTED
FETCH_SUCCEEDED
FETCH_FAILED

Finally, if it's succeeded; it returns the actual response, or an error object.

I have a component that should detect whether the operation has failed or not, preferably by subscribing to the FETCH_FAILED action and displaying an error message based on the type of the error (404/401 and other status codes)

export const fetchData = () => {
    return async (dispatch, getState) => {
        const appState = getState();

        const { uid } = appState.appReducer;

        await dispatch(fetchRequested());

        try {
            const response = await LookupApiFactory().fetch({ uid });

            dispatch(fetchSucceeded(response));

            return response;
        } catch (error) {
            dispatch(fetchFailed());

            return error;
        }
    }
}

I'm quite new to redux and react, so I'm a bit unsure if I'm heading in the right direction, any help would be appreciated.

3
You dont subscribe to the action. Rather you map your component to the store. when the store is updated, your component will re-render accordingly. You can do this by using the mapStateToProps.Sujit.Warrier
Yes, I understand that, and it's perfectly fine to do that when I need to display a text value or something like that, but when an action occurs, I need to run some code depending on its result, not sure how to do that.animaonline
this code is it in a normal class and not a react component?Sujit.Warrier
Yes, it's in a separate class.animaonline
I think I have a similar-ish problem to what you're having - I need to call a "success" function on the successful API call. However, I need to listen for that dispatched action so I can make a meaningful UI change (in my case, close a modal). It's not really something that can belong in the redux state. In Angular's ngxs state management library, you can subscribe to the store when a particular action has been dispatched. I basically need to do the same here, but with redux. I'm currently using callbacks, but it's dirty.Tom

3 Answers

5
votes

To implement a proper redux call back and storage mechanism you should have a store to keep all your data,

const store = createStore(todos, ['Use Redux'])

then, you dispatch data to store,

store.dispatch({
  type: 'FETCH_FAILED',
  text: reposnse.status //Here you should give the failed response from api
});

Then you can get the value from the store in any of your components using a subscribe function. It will be called any time an action is dispatched, and some part of the state tree may potentially have changed.

store.subscribe(()=>{
  store.getState().some.deep.property
})

This is a simple implementation of Redux. As your app grows more complex, you'll want to split your reducing function into separate functions, each managing independent parts of the state using combineReducers. You can get more information from redux.js site

0
votes

The most common approach is to use connect function from react-redux library. This is a HoC which subscribes to state changes. Take a look at this library, additionally it allows you to bind your action creators to dispatch, what gives you an ability to dispatch your actions from component.

You can use it like this:

import React from 'react';
import { connect } from 'react-redux';

const MyComponent = ({ data, error }) => (
  <div>
    {error && (
      <span>Error occured: {error}</span>
    )}

    {!error && (
      <pre>{JSON.stringify(data, null, 2)}</pre>
    )}
  </div>
);

const mapStateToProps = (state) => ({
  data: state.appReducer.data,
  error: state.appReducer.error
});

export default connect(mapStateToProps)(MyComponent);

You can use conditional rendering inside your jsx as I've shown above, or use guard clause, like this:

const MyComponent = ({ data, error }) => {
  if (error) {
    return (
      <span>Error occured: {error}</span>
    );
  }

  return (
    <pre>
      {JSON.stringify(data, null, 2)}
    </pre>
  );
}
0
votes

Assuming reducers,

for FETCH_FAILED action,you can put some meaningful flag indicating there are some failure.Based on that flag you can show error messages or do other action.

const testReducers =(state,actione)=>{

    case 'FETCH_FAILED' : {

        return {
            ...state,{ error_in_response : true }
        }
    };

    default : return state;
}

In your container,you can get that flag and passed it to your component.

Assuming combineReducers used to combine reducers;

const mapStateToProps=(state)=>{

    return {
        error_in_response : state.testReducers.error_in_response
    }
}
connect(mapStateToProps)(yourComponent)

In your component, this can be accessed using this.props.error_in_response