0

I'm trying to change the state of redux from my reducer after AJAXing a server, but for some reason when I change my state variable in the promise response it still doesn't change the state like I want to.

I mad my own interface for AXIOS:

export function my_post(url, json_data, success_callback, error_callback) {
  return axios({
    method: 'post',
    url: url,
    data: btoa(JSON.stringify(json_data)) || {},
    headers: {
      'X-XSRFToken': getCookie('_xsrf')
    }
  }).then(response => {
    if (success_callback)
      success_callback(response)
  }).catch(error => {
    if (error_callback)
      error_callback(error)
  })
}

I'm calling this function in my reducer like this:

export default (state = initState, action) => {
    switch(action.type) {
        case actionTypes.AJAX:
            my_post(
                '/ajax/url',
                {
                    content: 'some content'
                },
                (response) => {
                    state = {
                        ...state,
                        ts: response['ts']
                    }
                }
            )
            break
    }
    return state
}

also tried this:

export default (state = initstate, action) => {
    switch(action.type) {
        case actionTypes.AJAX:
            my_post(
                '/ajax/url',
                {
                    content: 'some content'
                }
            ).then(
                state = {
                    ...state,
                    ts: response['ts']
                }
            )
            break
    }
    return state
}

but when I get to the return state the ts argument doesn't exist.

What am I missing here?

Elon Salfati
  • 1,537
  • 6
  • 23
  • 46
  • 1
    The issue is you are trying to do an Asyncrhonous action inside of a reducer. The action should be taking place inside of an action which then calls the reducer on completion. Please read this on why Redux Stores only support Synchronous Data flow: https://stackoverflow.com/questions/34570758/why-do-we-need-middleware-for-async-flow-in-redux – SteveB Jan 10 '18 at 14:37

2 Answers2

2

Your proposal doesn't seem like a standard implementation of redux.

The typical structure is for actions to be called and then when the action completes an event and data get dispatched to all reducers. The listening reducers decide if the event applies to it and then changes its data appropriately. This data is then returned to the UI and needs to be mapped from the state to the props of the component.

For your code, this means the axios call should be called as an action. When the call returns, either successfully or unsuccessfully, an event should be dispatched which the reducer receives and where the data is restructured with the data from the event data.

Any serious data processing or thinking shouldn't happen in the reducer. The reducer should just be consuming data from the action.

I have an example on my Github of a simplistic implementation of what I am talking about here: https://github.com/NickDelfino/nextjs-with-redux-and-cloud-firestore

It doesn't apply perfectly but shows the concepts I discussed above.

I also think you may need to use Redux-Thunk to do the network calls as you want. Documentation and the code can be found here: https://github.com/gaearon/redux-thunk

I would also recommend going over the redux basics on their website here: https://redux.js.org/docs/basics/

Feel free to ask more questions! I hope this was helpful!

Runner5
  • 104
  • 1
  • 8
1

API calls should happen in your action. You can use an additional package for async side effects in redux actions. Take a look at redux-thunk or redux-saga. But @SteveB is right. Never have any side effects in your reducers. They should be pure. From the redux docs:

Things you should never do inside a reducer:

  • Mutate its arguments;
  • Perform side effects like API calls and routing transitions;
  • Call non-pure functions, e.g. Date.now() or Math.random().
trixn
  • 15,761
  • 2
  • 38
  • 55