React/Redux - Not dispatching action

2019-08-31 03:59发布

问题:

I am new to react redux. I am trying to build a simple restaurant app with foursquare api. I have two actions which makes api calls to 1st. search the restaurant and 2nd one to fetch details like this.

Action.js

export const fetchVenueDetail = venueId => dispatch => {
  console.log("dispatching");
  dispatch({ type: FETCH_VENUE_REQUESTED });
  fetch(
    `https://api.foursquare.com/v2/venues/${venueId}? 
     client_id=${api_id}&client_secret=${api_key}&v=20180422`
  )
    .then(res => res.json())
    .then(data => dispatch({ type: FETCH_VENUE, payload: 
     data.response.venue }))
    .catch(err => console.log(err));
};

Here is my component

class VenueDetail extends Component {
  componentDidMount() {
    this.props.fetchVenueDetail(this.props.match.params.id);
  }
  render() {
    console.log(this.props);
    const { venue, isLoading } = this.props;
    console.log("This text", venue);
    return (
      <React.Fragment>
        <Header type="venueDetail" venueDetail={venue} />
        <main className="main-content">
          <section className="venue">
            { !isLoading ? <ImageList venueDetail={venue} /> : <Loader /> }
          </section>
          <div className="sidebar-wrapper">
            <Sidebar type="tips" venueDetail={venue} />
          </div>
        </main>
      </React.Fragment>
    )
  }
};

const mapStateToProps = state => ({
  venue: state.venueReducer.venue,
  isLoading: state.venueReducer.isLoading
})

export default connect(mapStateToProps, {fetchVenueDetail})(VenueDetail);

After testing I figured out it is not dispatching the action that's why I am receiving an empty response.

Here is the working sandbox code If anyone wants to check- https://codesandbox.io/s/7m4153p1jq

回答1:

The actual problem, that you're getting error before your request starts in Sidebar component. There is no groups property in your venue object until your request is done.

If you add such check in your "tips" case it should run well:

const itemTips = venueTips.tips.groups ? venueTips.tips.groups[0].items : []; 

You can add groups to your reducer and check for length property or choose another way, like wrapping all of the component, including Sidebar component, and display Loader instead of them. Something like this:

VenueDetail.js

{
    (!isLoading && venue.id) ?
        <React.Fragment>
            <section className="venue">
                <ImageList venueDetail={venue}/>
            </section>
            <div className="sidebar-wrapper">
                <Sidebar type="tips" venueDetail={venue}/>
            </div>
        </React.Fragment> : <Loader/>
}

Here is updated codesandbox.



回答2:

Ok So the problem was I was dispatching my action inside componentDidMount lifecycle but when i changed it back to componentWillMount. It works. Can somebody explain why?