ARMATAV
ARMATAV

Reputation: 634

Modifying state with promises

Why do my promises not actually update the state in Redux?

I'm using redux-promise-middleware. When I make a call to my API, it goes through the promise steps of _PENDING and _FULFILLED, but the state is never updated to reflect the changes.

How do I do this properly, so that I actually get my data.


Here's a picture of my state:

_PENDING and _FULFILLED state

As you can see, isFetched does not become true after the promise is fulfilled, and data is never loading the returned response data into itself.


This is my API helper:

class UserAPI {

     ...

     async testPhone(user) {
         await axios.post(this.testPhonePath, {
             phone: user.phone
         })
         .then(function(response) {
             return response.data
         })
         .catch(function(error) {
             return error.response.data
         })
     }
}

My action:

import { UserAPI } from '../../constants/api'

const userAPI = new UserAPI()

export const TEST_USER_PHONE = 'TEST_USER_PHONE'

export const testUserPhone = (user) => ({
    type: TEST_USER_PHONE,
    payload: userAPI.testPhone(user)
})

And my reducer:

import {
    TEST_USER_PHONE
} from './actions'

const INITIAL_STATE = {
    testedByPhone: {
        data: [],
        isFetched: false,
        error: {
            on: false,
            message: null
        }
    }
}

export default (state = INITIAL_STATE, action) => {
    switch(action.type) {
        case '${TEST_USER_PHONE}_PENDING':
            return INITIAL_STATE
        case '${TEST_USER_PHONE}_FULFILLED':
            return { 
                testedByPhone: {
                    data: action.payload,
                    isFetched: true,
                    error: {
                        on: false,
                        message: null
                    }
                }
            }
        case '${TEST_USER_PHONE}_REJECTED':
            return { 
                testedByPhone: {
                    data: [],
                    isFetched: true,
                    error: {
                        on: true,
                        message: action.payload
                    }
                }
            }
        default:
            return state
    }
}


Here's my Store

import { createStore, applyMiddleware, compose } from 'redux'
import promiseMiddleware from 'redux-promise-middleware'

import reducers from './reducers'

const middleware = [
    promiseMiddleware()
]

if (__DEV__) {
    const logger = require('redux-logger')

    middleware.push(logger())
}

const enhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose

export default createStore(
    reducers,
    undefined,
    enhancers(applyMiddleware(...middleware))
)

Upvotes: 0

Views: 101

Answers (2)

Oskar
Oskar

Reputation: 2607

The reason it isn't working, it is that you use a standard string instead of JS templates. Replace:

'${TEST_USER_PHONE}_REJECTED'

With:

`${TEST_USER_PHONE}_REJECTED`

Upvotes: 2

Bergi
Bergi

Reputation: 664886

I suspect you wanted to use either

testPhone(user) {
    return axios.post(this.testPhonePath, {
        phone: user.phone
    }).then(function(response) {
        return response.data
    }, function(error) {
        return error.response.data
    });
}

or

async testPhone(user) {
    try {
        const response = await axios.post(this.testPhonePath, {
            phone: user.phone
        });
        return response.data
    } catch(error) {
        return error.response.data
    }
}

but not that current mix which always returns a promise for undefined - it only uses await but not return.

Upvotes: 0

Related Questions