0

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))
)
ARMATAV
  • 604
  • 6
  • 26
  • 1
    the function `testPhone` doesn't return anything - is that correct? – Jaromanda X Mar 28 '17 at 23:19
  • Your `testPhone` function doesn't return anything – Bergi Mar 28 '17 at 23:20
  • Doesn't it return `response.data` or `error.response.data` depending? I'm confused. – ARMATAV Mar 28 '17 at 23:21
  • are you applying the middleware when you create the store? – Matt Aft Mar 28 '17 at 23:36
  • @MattAft yeah I believe I am, added store to show – ARMATAV Mar 28 '17 at 23:38
  • are you sure redux devtools works with react native? I was reading somewhere it didn't but they mightve updated it – Matt Aft Mar 28 '17 at 23:49
  • @MattAft Seems like it's working fine for me - also this dude's tutorial at this time shows a working version of my stuff: http://www.youtube.com/watch?v=kNkTQtRUH-M&t=29m8s – ARMATAV Mar 28 '17 at 23:55
  • 2
    It seems like in the switch statement you wanted to use new JS templates but actually you used just a standard string. Try replacing ' with \`, so: `'${TEST_USER_PHONE}_PENDING'` to `\`${TEST_USER_PHONE}_PENDING\`` – Oskar Mar 29 '17 at 00:04
  • @Oskar TOTALLY WORKED replacing the ' with a ` god damn it that's the second time new JS stuff has wrecked my workflow. Post as an answer please - niiiiiiiice! – ARMATAV Mar 29 '17 at 00:07
  • 1
    Cool! Ok, I'm posting the answer. – Oskar Mar 29 '17 at 00:08

2 Answers2

2

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`
Oskar
  • 2,548
  • 1
  • 20
  • 22
  • 1
    This is why you shouldn't do drugs before coding. Thanks so much for the answer dude - 10/10. – ARMATAV Mar 29 '17 at 00:11
0

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.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Actually, I just tried both of those - and while I think what you're saying makes sense and it was a fundamental misunderstanding of promises/async-await - it didn't update my state still. `isFetched` is still false when fulfilled. – ARMATAV Mar 28 '17 at 23:29
  • Hm, I have to admit that I have no idea of redux :-/ – Bergi Mar 28 '17 at 23:35