Search code examples
javascriptreactjsreduxredux-thunk

Redux state wont propagate to component


I've been attempting to make a component using Reacts component functionality. In this case I was particularly interested in componentDidMount.

However, no matter what I try, my state wont propagate to the component.

Here is the component:

class MainPage extends React.Component
{
    componentDidMount() {
        this.props.actions.requestPosts();
    }
    render() {
        return(
            <div className="main-page">
                <PreviewList posts={this.props.posts}/>
            </div>
        );
    }
}

const mapStateToProps = state => ({
    posts: state.main_posts,
    errors: state.main_errors
});

const mapDispatchToProps = dispatch => {
    return {
        actions: {
            requestPosts: () => dispatch(requestPosts())
        }
    }
};

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

The reducer:

export default (state = {main_posts: [], main_errors: []}, action) => {
    switch(action.type) {
        case USER_REQUESTS_POSTS_SUCCEEDED:
            return Object.assign({}, state, {
                main_posts: action.posts
            });
        case USER_REQUESTS_POSTS_FAILED:
            return Object.assign({}, state, {
                main_errors: action.errors
            });
        default:
            return state;
    }
};

For the purpose of simplicity, I did not include the import statements. I use redux-thunk. I've tested the actions, they successfully arrive at the reducer. The new state is successfully created and returned. It simply does not arrive at the desired component however.

I have tried researching and I've only found examples of reducers that mutated the state, but I can't see anything where I mutate the state. What am I doing wrong? (Ironically the code is similiar to my other react apps that work fine).

In case it is helpful, here is my store:

export const history = createHistory();

const middleware = [
    thunk,
    routerMiddleware(history)
];

const reducers = {
    main: mainReducer,
    router: routerReducer
};

const store = createStore(
    combineReducers(reducers),
    {},
    applyMiddleware(...middleware)  
);

export default store;

EDIT: As requested, here are my actions:

export const USER_REQUESTS_POSTS_SUCCEEDED = 'user/REQUESTS/POSTS/SUCCESS';
export const USER_REQUESTS_POSTS_FAILED = 'user/REQUESTS/POSTS/FAILURE';

export const requestPosts = () => {
    return function(dispatch) {
        return fetchPosts().then(
            posts => dispatch(requestPostsSucceeded(posts)),
            errors => dispatch(requestPostsFailed(errors))
        );
    };
};

function fetchPosts() {
    return Promise.resolve([{title: 'Test Post', content_short: 'Hello World', author: 'Extremo', category: 'development', tags: ['test'], date: '15.11.17'}]);
}

export const requestPostsSucceeded = (posts) => {
    return {type: USER_REQUESTS_POSTS_SUCCEEDED, posts: posts};
};

export const requestPostsFailed = (errors) => {
    return {type: USER_REQUESTS_POSTS_FAILED, errors: errors};
};

Solution

  • From store definition

    const reducers = {
        main: mainReducer,
        router: routerReducer
    };
    

    You should access your component state using your component reducer's key

    which is main.

    const mapStateToProps = state => ({
        posts: state.main.main_posts,
        errors: state.main.main_errors
    });