Ishan Patel
Ishan Patel

Reputation: 6091

Why action is not going through reducer?

I am trying to pull posts from WordPress blog.

In console, I am only getting one log for Blog component where this.props.posts is empty object. It should have second log when state changes after action passes through the reducer. I can even see successful xhr request for the posts in inspector.

Following is the component where I am firing action.

import React, {Component} from 'react';
import {Link} from 'react-router-dom';
import {connect} from 'react-redux';
import {fetchPosts} from '../../action/index';
class Blog extends Component {

    componentDidMount(){
        this.props.fetchPosts();
    }

    render(){
        console.log('Posts are: ',this.props.posts);
        return (
            <div>
                <Link to="/posts/new"><button> Add a New Post </button> </Link>                
            </div>
        );
    }
}
function mapStateToProps(state){
    return {
        posts: state.posts
    };
}


export default connect(mapStateToProps, {fetchPosts})(Blog);

Following is the reducer.

import FETCH_POSTS from '../action';
import _ from 'lodash';

function PostsReducer(state= {}, action){
    switch(action.type){

        case FETCH_POSTS:
        console.log('reducer: ', action.payload.data);
        return _.mapKeys(action.payload.data, 'id');


        default:
        return state;
    }
}

export default PostsReducer;

Index file for the combined reducer is following:

import {combineReducers} from 'redux';
import PostsReducer from './posts_reducer';

const rootReducer = combineReducers({
    posts: PostsReducer
});

export default rootReducer;

Here's the action creator file

import axios from 'axios';

export const FETCH_POSTS = 'fetch_posts';

const ROOT_URL = 'https://public-api.wordpress.com/rest/v1.1/sites/ishhaanpatel.wordpress.com/posts';

export function fetchPosts() {

    const request = axios.get(`${ROOT_URL}`);

    console.log('request is: ',request);

    return {
        type: FETCH_POSTS,
        payload: request
    };

}
export default fetchPosts;

Upvotes: 0

Views: 272

Answers (1)

Timm
Timm

Reputation: 168

Your action is asynchronous, so you need to dispatch it through some middle-ware like redux-thunk. See "Async Actions" in the official docs.

When you dispatch a plain action you can simply return the object literal, like this:

const actionCreator = () => ({ type: 'ACTION' })

but you want to attach a response payload to your action, so you need to wait until the request promise resolves and (if you are using thunks) return a function that takes dispatch as argument, which returns the actual action payload:

const asyncActionCreator = () => dispatch => {
  fetch('url')
  .then(response => dispatch({type: 'ACTION', payload: response}))
}

See above links for a deeper explanation and examples.

// edit

In case you are unfamiliar with the ES6 syntax:

function asyncActionCreator() {
  return function(dispatch) {
    fetch('url')
    .then(function(response) {
      dispatch({type: 'ACTION', payload: response})
    })
  }
}

Upvotes: 2

Related Questions