1
votes

I am trying to get familiar with the flow of the react-boilerplate. Till now I love how neat clean and easy to understand are things, I although feel that I miss a piece of the puzzle. Would be nice if someone with more experience could help me with that.

The problem I am facing at the moment goes as follows.

  • I am triggering an action within componentWillMount() of a specific component.
  • The action is being created in actions.js, its a simple get request made with axios.
  • The data are being processed in a promise middleware library redux-promise.
  • The promise is now being passed into the reducer of the specific component, where the whole state and the data that I need are being returned.
  • Trying to catch this state at the component is where I fail. I am trying to mapStateToProps but cannot find the data that I need there instead a Map {} is being received.

How do I Map this object with my props ?

I am sure I miss something important.

Here is my repo. https://github.com/paschalidi/blog-react-redux

And here is my code so you can have a brief look.

index.js

import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import { fetchPosts } from './actions'
import selectPostsIndex from './selectors'

export class PostsIndex extends React.Component { // eslint-disable-line react/prefer-stateless-function
  componentWillMount() {
    this.props.fetchPosts();
  }

  render() {
    return (
      <div>
        <h3>Posts</h3>
        <ul className="list-group">
          A list would render here. 
        </ul>
      </div>
    );
  }
}

function mapStateToProps(state) {
  console.log(state.posts)
  //return { posts: state } //****I dont get why the redux state is not being given here.
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({ fetchPosts }, dispatch);
}

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

actions.js

import axios from 'axios'
import { FETCH_POSTS } from './constants';

const ROOT_URL = 'http://reduxblog.herokuapp.com/api';
const API_KEY = '?key=dsklhfksdhfjkdshfkjdshkj';

export function fetchPosts() {
  const request = axios.get(`${ROOT_URL}/posts${API_KEY}`);
  return {
    type: FETCH_POSTS,
    payload: request
  };
}

store.js

import promise from 'redux-promise';

const middlewares = [
    sagaMiddleware,
    routerMiddleware(history),
    promise
  ];

reducer.js

import { fromJS } from 'immutable';
import {
  FETCH_POSTS
} from './constants';

const initialState = fromJS({ all:[], post: null });

function postsIndexReducer(state = initialState, action) {
  switch (action.type) {
    case FETCH_POSTS:
      return { ...state, all: action.payload.data };
    default:
      return state;
  }
}

export default postsIndexReducer;

Also the action is being registered in reducers.js

import PostsReducer from 'containers/PostsIndex/reducer'

export default function createReducer(asyncReducers) {
  return combineReducers({
    route: routeReducer,
    language: languageProviderReducer,

    posts: PostsReducer,
    form: reduxFormReducer,
    ...asyncReducers,
  });
}
2

2 Answers

1
votes

Note I didn't test your code, but it looks like your reducer puts the fetched data in the field all of your global states posts field, but your mapStateToProps doesn't pick that up. Note that mapStateToProps should slice the part of the global state that the given component is interested in.

After a successful fetch the state you receive in mapStateToProps should look something like this:

{
  posts: {
    all: // whatever fetch returned
    post: null
  }
}

So your mapStateToProps could look something like this (note that this method receives the global state as an argument, not just for the specific reducer):

function mapStateToProps(state) {
  // in component this.props.posts is { all: /* fetch result */, post: null }
  return { posts: state.posts } 
}

Also try to debug these methods, it becomes clearer once you see the flow of the data!

1
votes

This GitHub issue covers this exact problem: https://github.com/reactjs/react-redux/issues/60.

I had to manually extract the values from the Map in mapStateToProps function:

const mapStateToProps = (state) => {
  return {
       posts: state.get('posts'),
  };
}

Thanks to this StackOverflow post.