Joshua Rajandiran Joshua Rajandiran - 4 months ago 27
Javascript Question

Cannot read state from Redux store. What did I miss?

Here is my

index.js
where I initially dispatch an action to read my list of locations:

import 'babel-polyfill';
import React from 'react';
import { render } from 'react-dom';
import configureStore from './store/configureStore';
import {Provider} from 'react-redux';
import { Router, browserHistory } from 'react-router';
import routes from './routes';
import {loadLocationList} from './actions/locationActions';
import './css/styles.css';

const store = configureStore();

render(
<Provider store={store}>
<Router history={browserHistory} routes={routes} />
</Provider>,
document.getElementById('app')
);


Then here is my action where I get the data & then create an action out of it:

export function loadLocationListSuccess(alistingData) {
return { type: types.LOAD_LOCATION_LIST_SUCCESS, listingData: alistingData};
}

export function loadLocationList() {
return function(dispatch){ //we return a function that accepts a parameter, we just called it dispatch
//dispatch(fetchCallActions.fetchCallStart("")); // we dispatch a function fetchCallStart to indicate the start of our call, this is to keep in check with our asynchronous function calls
let link = 'http://example.com:8399/location';//our fetch url
console.log(link); //we log our link, just for debug purposes

return fetch(link) //start fetch
.then(function(response) {
return response.json();
}).then(function(json) {
dispatch(loadLocationListSuccess(json));
}).catch(function(ex) {
console.log('parsing failed', ex);

});
};
}


Then here is my reducer:

import * as types from '../actions/actionTypes';

export default function locationReducer(state = [], action) {
switch(action.type) {
case types.LOAD_LOCATION_LIST_SUCCESS:
return {listingData: action.listingData};
default:
return state;
}
}


Then here is my
mapStateToProps
&
connect
function:

function mapStateToProps(state, ownProps) {
return {
// we'll call this in our component -> this.props.listingData
listingData: state.listingData
};
}

export default connect(mapStateToProps, mapDispatchToProps)(homePage);


For some reason, it cannot read
state.listingData
or am I actually doing it wrongly? Anyone can help me with this problem?

I tried logging
state.listingData
and it showed
undefined


Here is my
configureStore
:

import {createStore, applyMiddleware} from 'redux';
import rootReducer from '../reducers';
import reduxImmutableStateInvariant from 'redux-immutable-state-invariant';
import thunk from 'redux-thunk';

export default function configureStore(initialState) {
return createStore(
rootReducer,
initialState,
applyMiddleware(thunk, reduxImmutableStateInvariant())
);
}


Here is my combined Reducer:

import {combineReducers} from 'redux';
import courses from './courseReducer';
import locations from './locationReducer';

const rootReducer = combineReducers({
courses,
locations
});


export default rootReducer;


Did I not connect it to the store properly?

Recent update:
Logging
JSON.stringify(state)
in
mapStateToProps
would actually shows the result. Thanks guys.

The correct path turned out to be
state.locations.listingData
because I think in my combined Reducer I included the reducer as
locations
so maybe thats why the state for it is
state.locations
. Hope this helps anyone with the problem.

Answer
  • Can you show the code of configureStore file? The problem might be there, may be you forgot to add reducer to list of reducers.
  • Does the action works right? Did you log data before dispatch(loadLocationListSuccess(json));?

UPD:

Because of rootReducer. Each reducer creates their own key in store. When you combine your reducers in rootReducer, like:

import locations from './locationReducer';
const rootReducer = combineReducers({
    courses,
    locations
});

It creates store with this kind of structure:

const store = {
    courses: {},
    locations: {}
}

So, after that you dispatched action and reducer changed the data to this:

const store = {
    courses: {},
    locations: {
       listingData: someData
    }
}

If you want to access to listingData like: state.listingData, you need to change a little your reducer and combineReducer to:

export default function listingData(state = {}, action) {
    switch(action.type) {
        case types.LOAD_LOCATION_LIST_SUCCESS:
            return action.listingData;
        default:
            return state;
    }
}

...

import listingData from './locationReducer';
const rootReducer = combineReducers({
    courses,
    listingData
});
Comments