2

I'm new into the React and Redux worlds and after a lot of research, I haven't found a way to handle the problem I have:

I need to perform an api call on app init, but the endpoint is in a configuration file. This configuration in the server so it has to be downloaded and read. This is because I need to distribute the app into many servers and each server has a different configuration.

Therefore the api call has to wait until the configuration has been loaded, they must be chained.

I'm using Redux to manage the state of the app so I have an action which downloads the configuration and an other action which performs the api call.

// Config action
export function fetchConfigRequest() {
    return {
        type: types.FETCH_CONFIG_REQUEST
    }
}

export function fetchConfigSuccess(config) {
    return {
        type: types.FETCH_CONFIG_SUCCESS,
        config
    }
}

export function fetchConfig() {
    return dispatch => {
        dispatch(fetchConfigRequest());

        return axios.get('config.json')
            .then(response => {
                dispatch(fetchConfigSuccess(response.data));
            })
        ;
    };
}
// Api client action
export function fetchDataRequest() {
    return {
        type: types.FETCH_DATA_REQUEST
    }
}

export function fetchDataSuccess(data) {
    return {
        type: types.FETCH_DATA_SUCCESS,
        data
    }
}

export function fetchDataError(error) {
    return {
        type: types.FETCH_DATA_ERROR,
        error
    }
}

export function fetchData(filters = {}) {

    return dispatch => {

        dispatch(fetchDataRequest());

        const apiClient = new apiClient({
            url: state.config.apiEndpoint
        });

        return apiClient.Request()
            .then(response => {
                dispatch(fetchDataSuccess(data));
            })
        ;
    };
}

The only way that I got it working is by waiting until config action promise resolves in App component like this:

// App.component.js
componentDidMount() {
    this.props.fetchConfig().then(() => {
        this.props.fetchData();
    });
}

But I don't think this is the best and the most "Redux style" way to do it, so how should I do it?

I've some ideas in my mind but I don't know what would be the best one:

  • Keep it as it is now
  • Create an 'app' action which dispatches the fetch config action, waits until config is loaded, and then dispatches the fetch data action
  • Do it into a custom middleware

Thanks!

Carles
  • 180
  • 2
  • 12
  • 2
    Have you had a look at redux-saga? – Nikita Malyschkin Jan 18 '19 at 11:21
  • 1
    Is there a reason why you can't dispatch the fetchData action from within the then method of your fetch config promise? – David Hall Jan 18 '19 at 12:00
  • @NikitaMalyschkin I'll have a look to redux-saga, thanks. – Carles Jan 21 '19 at 08:30
  • @DavidHall I think it would be better to create a new action which firstly fetches the config and then the data, woudn't it? – Carles Jan 21 '19 at 08:32
  • @Carles that would still be what you have. You have the same actions, but just dispatch the fetchData action from the fetchConfig action. There is nothing wrong with doing that - it is exactly the problem that redux-thunk is meant to solve. Of course, this then couples your two actions, so the design might not be quite right for you. If you need something different then sagas are another approach that gives a slightly different design. – David Hall Jan 21 '19 at 10:15
  • As you rightly feel, passing the promise back to the component is the worst option, since that then forces your component to know about the backend loading of data, including the requirements like the config needing to be there before fetching. – David Hall Jan 21 '19 at 10:16
  • 1
    @Carles oh sorry, I think I misread your comment slightly. You mean have one new action the first calls the fetchConfig action and then calls the fetch config? Yes, that would probably be best. You would need to check that all the async bits and pieces happen in the right order. redux-thunk and dispatch all work synchronously, but I'm not 100% sure how that ties into the async api request. Probably you need to pass the promise back out (or use async await) and then have a then method in the parent action. – David Hall Jan 21 '19 at 10:20

0 Answers0