0
votes

I am having a react-redux action creation problem. My props are an empty object when I log props at the life cycle method componentDidMount()

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchSurveys } from '../../actions/index';

export class SurveyList extends Component {
 componentDidMount() {
   console.log(this.props);
   this.props.fetchSurveys();
 }

  renderSurveys() {
    return (
   this.props.surveys.length &&
    this.props.surveys.map(survey => {
     return (
       <div className="card blue-grey darken-1" key={survey._id}>
         <div className="card-content">
           <span className="card-title">{survey.title}</span>
           <p>{survey.body}</p>
           <p className="right">
             Sent On: {new Date(survey.dateSent).toLocaleDateString()}
           </p>
          </div>
          <div className="card-action">
            <a>Yes: {survey.yes}</a>
            <a>No: {survey.no}</a>
          </div>
        </div>
      );
    })
  );
}

 render() {
  return <div>{this.renderSurveys()}</div>;
  }
}

function mapStateToProps({ surveys }) {
 return { surveys };
 }

  export default connect(mapStateToProps, { fetchSurveys })(SurveyList);

Now according to the react-redux docs by default dispatch is included on the props so we do not need to explicitly call a mapDispatchToProps in the connect method in order to hit our action creators. fetchSurveys() is an action creator and I expect it to return a list of surveys which I then render.

However this.props = {}; so of course I cannot call .map on undefined at renderSurveys() as I do not get the surveys property on props either.

I am really troubled by why my props are empty. Can anybody shed some light onto this problem, I would be very grateful. I have tried using bindActionCreators and having my own mapDispatchToProps method, this doesn't work either.

Here are my actions.

import axios from 'axios';
import { FETCH_USER, FETCH_SURVEYS } from './types';

export const fetchUser = () => async dispatch => {
  const res = await axios.get('/api/current_user');

 dispatch({ type: FETCH_USER, payload: res.data });
 };

export const handleToken = token => async dispatch => {
  const res = await axios.post('/api/stripe', token);
  dispatch({ type: FETCH_USER, payload: res.data });
};

export const submitSurvey = (values, history) => async dispatch => {
 const res = await axios.post('/api/surveys', values);

 history.push('/surveys');
 dispatch({ type: FETCH_USER, payload: res.data });
};

export const fetchSurveys = () => async dispatch => {
 console.log('called');
 const res = await axios.get('/api/surveys');

 dispatch({ type: FETCH_SURVEYS, payload: res.data });
};

My surveys reducer -

import { FETCH_SURVEYS } from '../actions/types';

export default function(state = [], action) {
  switch (action.type) {
    case FETCH_SURVEYS:
      return action.payload;
    default:
      return state;
  }
}

enter image description here

Props in console - enter image description here

Combined reducer -

import { combineReducers } from 'redux';
import authReducer from './authReducer';
import { reducer as reduxForm } from 'redux-form';
import surveysReducer from './surveysReducer';

export default combineReducers({
 auth: authReducer,
 form: reduxForm,
 surveys: surveysReducer
});
3
this.props.dispatch(fetchSurveys() is what to docs mean. The dispatch isn't automatically wired up unless you use bindActionCreators. You probably need to default surveys to [] as well. - Davin Tryon
@Davin Tryon as per github.com/reactjs/react-redux/blob/master/docs/api.md#examples : "If you do not supply your own mapDispatchToProps function or object full of action creators, the default mapDispatchToProps implementation just injects dispatch into your component’s props." - godhar

3 Answers

1
votes

Just saw your code in the link. In Dashboard.js

Shouldn't

import { SurveyList } from './surveys/SurveyList';

be

import SurveyList from './surveys/SurveyList';

Since the connected component is exported as default?

0
votes

Have you used your reducer in combineReducers? you should have an index.js file in reducers folder (for example) which has something like this:

import {myreducer} from './myreducer';

const rootReducer = combineReducers(
    {
        myreducer: myreducer
    }
);

export default rootReducer;

Do you have complete codebase somewhere? It looks like issue is not in provided code..

0
votes

Seems that you forgot to add your reducer to main reducers file.

So, it depends on your code it should be:

// reducers/index.js

import { combineReducers } from 'redux';
import surveys from './surveysReducer';

const rootReducer = combineReducers({
    surveys,
});

export default rootReducer;

Hope it will helps.