title: react router not loading id and handling error
body: <p>I have tried to follow the udemy guide to implement react router. the problem i have is when loading the page directly with an id without going through a list page first. it does not seem to load the records. i want to go to page <code>/commsmatrix/approve/121</code> and load record <code>121</code>.  i am using <code>react router v4</code>. in <code>mapStateToProps</code>, <code>records</code> is <code>undefined</code></p>
  
  <p>approve.js</p>
  
  <pre><code>import React, { Component } from 'react';
  import { connect } from 'react-redux';
  import { fetchCommsmatrix } from '../../actions/commsmatrices';
  import { bindActionCreators } from 'redux';
  import FontAwesome from 'react-fontawesome';
  
  class Approve extends Component {
      constructor(props) {
          super(props);
          this.meta = { title: 'Comms Matrix Approval', description: 'Sox approval' };
          this.runOnce = false;
          this.passMetaBack = this.passMetaBack.bind(this);
          this.initConfirm = this.initConfirm.bind(this);
      }
  
      componentDidMount() {
          this.passMetaBack;
          const { id } = this.props.match.params.id;
          this.props.fetchCommsmatrix(id);
      }
  
      passMetaBack = () =&gt; {
          this.props.passMetaBack(this.meta);
      };
  
      initConfirm(){
          this.runOnce = true;
          /*this.props.fetchCommsmatrix(121)
          .then(function(response){
              console.log(response);
              let data = response.payload.data;
              if(data.header.error){
                  self.setState({ 
                      showError: true,
                      errorMsg: data.header.message
                  });
              }else{
  
              }
          });*/
  
      }
  
      render() {
          console.log(this);
          if(!this.runOnce &amp;&amp; this.props.isReady){
              this.initConfirm();
          }
  
          const { record } =  this.props ;
          console.log(record);
  
          let message = &lt;div&gt;Confirming...&lt;i className="fa fa-spinner fa-spin"&gt;&lt;/i&gt;&lt;/div&gt;;
          return (
              &lt;div className="container-fluid"&gt;
                  &lt;div className="row-fluid top-buffer"&gt;{message}&lt;/div&gt;
              &lt;/div&gt;
          );
      }
  }
  
  function mapStateToProps({ records }, ownProps) {
      console.log(records);
  console.log(ownProps);
      return { record : records[ownProps.match.params.id] };
  }
  
  function mapDispatchToProps(dispatch) {
      return bindActionCreators(
          { fetchCommsmatrix },
          dispatch
      );
  }
  
  export default connect(mapStateToProps, { fetchCommsmatrix })(Approve);
  </code></pre>
  
  <p>here is my <strong>actions</strong> </p>
  
  <pre><code>import axios from 'axios';
  
  export const FETCH_COMMSMATRIX = 'fetch_commsmatrix';
  
  export function fetchCommsmatrix(id) {
      const request = axios.get(`/api/user/comms/matrices/id/`+id+`/format/json?quiet=1`);    
      return {
          type: FETCH_COMMSMATRIX,
          payload: request
      };
  }
  
  export const FETCH_COMMSMATRICES_BY_SERVICE = 'fetch_commsmatrices_by_service';
  
  export function fetchCommsmatricesByService(service_id) {
      const request = axios.get(`/api/user/comms/matrices/format/json?quiet=1&amp;service_id=`+service_id);   
      return {
          type: FETCH_COMMSMATRICES_BY_SERVICE,
          payload: request
      };
  }
  </code></pre>
  
  <p>here is my <strong>reducer</strong></p>
  
  <pre><code>import { FETCH_COMMSMATRIX, FETCH_COMMSMATRICES_BY_SERVICE } from '../actions/commsmatrices';
  
  export default function(state = {}, action) {
      switch (action.type) {
      case FETCH_COMMSMATRIX:
          return { ...state, [action.payload.data.body.recordset.record[0].id] : action.payload.data.body.recordset.record[0] };
      case FETCH_COMMSMATRICES_BY_SERVICE:        
          return action.payload.data.body.recordset.record;
      default:
          return state;
      }
  }
  </code></pre>
  
  <p>here is <strong>index reducer</strong></p>
  
  <pre><code>import { combineReducers } from 'redux';
  import { reducer as formReducer } from 'redux-form'; 
  import ActiveUserReducer from './reducer_active_user';
  import CommsmatricesReducer from './reducer_commsmatrices';
  import ContentReducer from './reducer_content';
  import ContentVideListReducer from './reducer_content_video_list';
  import SecurityExemptionsReducer from './reducer_security_exemption';
  import ReportsWorkerJobs from './reducer_reports_workerjobs';
  import ReportsWorkerJobsCount from './reducer_reports_workerjobs_count';
  import ReportsFactsandfigures from './reducer_reports_factsandfigures';
  import ReportsFactsandfiguresCount from './reducer_reports_factsandfigures_count';
  import ServicesReducer from './reducer_services';
  import ServicesEditCheckReducer from './reducer_services_edit_check';
  import ServicesAddReducer from './reducer_services_add';
  import ServicesRenameReducer from './reducer_services_rename';
  import ServicesRemoveReducer from './reducer_services_remove';
  import TemplatesReducer from './reducer_templates';
  
  const rootReducer = combineReducers({
      form: formReducer,
      activeUser: ActiveUserReducer,
      commsmatrices: CommsmatricesReducer,
      content: ContentReducer,
      contentVideoList: ContentVideListReducer,
      reportsWorkerJobs: ReportsWorkerJobs,
      reportsWorkerJobsCount: ReportsWorkerJobsCount,
      securityExemptions: SecurityExemptionsReducer,
      reportsFactsAndFigures: ReportsFactsandfigures,
      reportsFactsAndFiguresCount: ReportsFactsandfiguresCount,
      services: ServicesReducer,
      servicesEditCheck: ServicesEditCheckReducer,
      servicesAdd: ServicesAddReducer,
      servicesRename: ServicesRenameReducer,
      servicesRemove: ServicesRemoveReducer,
      templatesReducer: TemplatesReducer
  });
  
  export default rootReducer;
  </code></pre>
  
  <p>here is <strong>app</strong></p>
  
  <pre><code>import React, { Component } from 'react';
  import { Switch, Route, withRouter, Redirect } from 'react-router-dom';
  import ReactGA from 'react-ga';
  import { connect } from 'react-redux';
  import { fetchActiveUser } from './actions/index';
  import { bindActionCreators } from 'redux';
  import { getHttpRequestJSON } from './components/HTTP.js';
  
  import Header from './components/header';
  import Logout from './components/logout';
  import SideBar from './components/sidebar';
  import HomeContent from './containers/home';
  import Ldapuser from './components/ldapuser';
  import Admin from './components/admin/admin';
  import Services from './components/services/index';
  import SecurityExemptionsNew from './components/security/security_exemptions_new';
  import WorkerJobs from './components/reports/workerjobs';
  import FactsAndFigures from './components/reports/factsandfigures';
  import Approve from './components/commsmatrix/approve';
  import CommsMatrixTemplates from './components/commsmatrix/templates';
  import CommsMatrixTemplate from './components/commsmatrix/template';
  
  ReactGA.initialize('UA-101927425-1');
  
  function fireTracking() {
      ReactGA.pageview(window.location.pathname + window.location.search);
  }
  
  class App extends Component {
      constructor(props) {
          super(props);
          this.state = {
              isGuest: false,
              isSupp: false,
              priv: [],
              loading: true,
              version: '',
              redirect: false,
              title: 'Home',
              description: '',
              isReady: false
          };
      }
  
      setRedirect = () =&gt; {
          this.setState({
              redirect: true
          });
      };
  
      renderRedirect = () =&gt; {
          //if (this.state.redirect) {
              return &lt;Redirect to="/SSOLogon/manual_login.jsp" /&gt;;
          //}
      };
  
      initData = () =&gt; {
          let self = this;
  
          getHttpRequestJSON(
              '/api/user/get/user/method/is/guest/format/json?quiet=1'
          )
              .then(response =&gt; {
                  let isGuest = response.body.recordset.record.isGuest;
                  if (isGuest) {
                      /*$(".logo").trigger('click');
              //$("#overlay").show();
              $('#modalIntro').modal('toggle');
  
              $("#modalIntro").on("hidden.bs.modal", function () {
                $(".logo").trigger('click');
              });*/
                  }
  
                  //self.props.isGuest = isGuest;
                  //self.props.loading = false;
                  //self.props.version = response.header.version;
                  self.setState({
                      loading: false,
                      version: response.header.version,
                      isGuest: isGuest
                  });
              })
              .catch(error =&gt; {
                  console.log('Failed!', error);
                  //$('#myModalError .modal-body').html(error);
                  //$('#myModalError').modal('show');
              });
  
          getHttpRequestJSON(
              '/api/user/get/user/method/is/supp/format/json?quiet=1'
          )
              .then(response =&gt; {
                  self.setState({
                      isSupp: response.body.recordset.record.isSupp
                  });
              })
              .catch(error =&gt; {
                  console.log('Failed!', error);
                  //$('#myModalError .modal-body').html(error);
                  //$('#myModalError').modal('show');
              });
  
          getHttpRequestJSON(
                  '/api/user/get/user/method/priv/format/json?quiet=1'
              )
                  .then(response =&gt; {
                      self.setState({
                          priv: response.body.recordset.record
                      });
                  })
                  .catch(error =&gt; {
                      console.log('Failed!', error);
                      //$('#myModalError .modal-body').html(error);
                      //$('#myModalError').modal('show');
                  });
      };
  
      componentDidMount() {
          let self = this;
          this.props.fetchActiveUser()
          .then(() =&gt; {
              self.initData();
  
          })
          .then(() =&gt; {
              self.setState({
                  isReady : true
              });
          })
          if (this.props.activeUser.name == 'AuthError') {
  
              this.setRedirect();
          }
  
      }
  
      passMetaBack = (meta) =&gt; {
          this.setState({
              title: meta.title,
              description: meta.description
          })
      }
  
      render() {
          if (this.props.activeUser.name == 'AuthError') {
              //console.log('redirect');
              this.renderRedirect();            
          }
          return (
              &lt;div&gt;
                  &lt;Header
                      activeUser={this.props.activeUser}
                      loading={this.state.loading}
                      version={this.state.version}
                      title={this.state.title}
                      description={this.state.description}
                  /&gt;
                  &lt;SideBar isReady={this.state.isReady} /&gt;
                  &lt;main&gt;
                      &lt;Switch&gt;
                          &lt;Route
                              path="/commsmatrix/approve/:id"
                              component={Approve}
                          /&gt;
                      &lt;/Switch&gt;
                  &lt;/main&gt;
              &lt;/div&gt;
          );
      }
  }
  
  //export default App;
  function mapStateToProps(state) {
      if (state.activeUser.id &gt; 0) {
          ReactGA.set({ userId: state.activeUser.id });
      }
      // Whatever is returned will show up as props
      // inside of the component
      return {
          activeUser: state.activeUser
      };
  }
  
  // Anything returned from this function will end up as props
  // on this container
  function mapDispatchToProps(dispatch) {
      // Whenever getUser is called, the result should be passed
      // to all our reducers
      return bindActionCreators({ fetchActiveUser }, dispatch);
  }
  
  //Promote component to a container - it needs to know
  //about this new dispatch method, fetchActiveUser. Make it available
  //as a prop
  export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App));
  </code></pre>
  
  <p><strong>index.js</strong></p>
  
  <pre><code>import './scripts/api';
  import React, { Component } from 'react'
  import ReactDOM from 'react-dom';
  import { Provider } from 'react-redux';
  import { createStore, applyMiddleware, combineReducers } from 'redux';
  import { BrowserRouter, Route, browserHistory } from 'react-router-dom';
  import promise from 'redux-promise';
  import App from './App'
  import reducers from './reducers';
  import 'react-quill/dist/quill.snow.css'; // ES6
  
  require("babel-core/register");
  require("babel-polyfill");
  
  const createStoreWithMiddleware = applyMiddleware(promise)(createStore);
  
  ReactDOM.render(
          &lt;Provider store={createStoreWithMiddleware(reducers)}&gt;
              &lt;BrowserRouter history={browserHistory}&gt;
                  &lt;App/&gt;
              &lt;/BrowserRouter&gt;
          &lt;/Provider&gt;
          , document.getElementById('root'));
  </code></pre>
  
  <p><strong>UPDATE</strong></p>
  
  <p>so I have updated <code>records</code> to match reducer name. seems to work but need a way to handle errors when there are no records</p>
  
  <pre><code>import React, { Component } from 'react';
  import { connect } from 'react-redux';
  import { fetchCommsmatrix } from '../../actions/commsmatrices';
  import { bindActionCreators } from 'redux';
  import FontAwesome from 'react-fontawesome';
  
  class Approve extends Component {
      constructor(props) {
          super(props);
          this.meta = { title: 'Comms Matrix Approval', description: 'Sox approval' };
          this.runOnce = false;
          this.passMetaBack = this.passMetaBack.bind(this);
          this.initConfirm = this.initConfirm.bind(this);
      }
  
      componentDidMount() {
          this.passMetaBack;
          const id = this.props.match.params.id;
          this.props.fetchCommsmatrix(id);
      }
  
      passMetaBack = () =&gt; {
          this.props.passMetaBack(this.meta);
      };
  
      initConfirm(){
          this.runOnce = true;
      }
  
      render() {
  
          let message = &lt;div&gt;Confirming...&lt;i className="fa fa-spinner fa-spin"&gt;&lt;/i&gt;&lt;/div&gt;;
  
          const { commsmatrix } =  this.props ;
  
          if(!this.runOnce &amp;&amp; this.props.isReady &amp;&amp; Object.keys(commsmatrix).length &gt; 0 ){
              this.initConfirm();
          }
  
          return (
              &lt;div className="container-fluid"&gt;
                  &lt;div className="row-fluid top-buffer"&gt;{message}&lt;/div&gt;
              &lt;/div&gt;
          );
      }
  }
  
  function mapStateToProps({ commsmatrices }, ownProps) {
  
      return { commsmatrix : commsmatrices[ownProps.match.params.id] };
  }
  
  function mapDispatchToProps(dispatch) {
      return bindActionCreators(
          { fetchCommsmatrix },
          dispatch
      );
  }
  
  export default connect(mapStateToProps, { fetchCommsmatrix })(Approve);
  </code></pre>