反应错误处理获取数据场地列表

时间:2018-08-26 21:20:13

标签: reactjs error-handling conditional foursquare

我正在使用Google Map API和react-google-map在React应用中使用Foursquare API来获取数据。

当我创建场所列表并尝试通过从API链接中删除一些字符来检查错误处理是否有效时,由于场所状态为空,应用程序崩溃。

我应该在映射数据的函数中添加条件语句以检查其是否为空,但我不知道该怎么做。

这是我的存储库:

https://github.com/Katesold/Watford-Map

如果有人可以建议我如何做,我将不胜感激。

我一直在尝试的内容如下:

filterCafes = (cafes, query) => {
    cafes !== undefined ? cafes.filter(cafe => 
    cafe.name.toLowerCase().includes(query.toLowerCase())): "error";
}

这是我得到的错误: app crashes

1 个答案:

答案 0 :(得分:1)

欢迎使用StackOverflow。

通过确保默认情况下将cafe设置为null可以缓解您的问题。然后在Sidebar1.js中,我向您在render方法(cafePlaces && cafePlaces.filter...)中使用的过滤器添加了一个真实检查。这意味着只有在您从中获取数据的父组件中成功获取cafePlaces时,才会执行过滤器。

您还需要更新Places.js,因为您也在那里使用咖啡馆。我还为filterCafes方法添加了一个早日返回的方法,因为当您尝试过滤时会出错,因为如果API调用失败,则由于没有将咖啡馆加载到父状态,因此会出错。

(请注意,在下面提供的示例代码中,我故意中断了您的API调用)。

App.js

import React, { Component } from "react";
import Map from "./Map";
import SideBar from "./SideBar1.js";
import "./App.css";
import Header from "./Header.js";
import Footer from "./Footer.js";

class App extends Component {
  state = {
    cafes: null,
    clickedCafe: {},
    filteredCafe: []
  };

  // get the data for the cafes in Watford and catch any errors from Foursquare and Map
  componentDidMount() {
    fetch(
      "https://api.foursquare.com/v2/venues/search?ll=51.656489,-.39032&intent=browse&radius=10000&client_id=XQSXUGIR140AWUVFJJ120S31IPIXQYIO2QJ2ZN2U0ZPLLG4P&client_secret=A0N5P5VI4NG5UQK2GV2M0WU1FYY3KZ0EUYV0YMYZSX5IHHSU&v=26"
    )
      .then(response => response.json())
      .then(data => {
        this.setState({
          cafes: data.response.venues,
          filteredCafe: data.response.venues
        });
      })
      .catch(error => {
        alert(
          "An error occurred while trying to fetch data from Foursquare: " +
            error
        );
      });

    window.gm_authFailure = () => {
      alert("An error occurred while trying to load Google Map");
    };
  }

  // Update filtered list of venues
  updateList = filteredCafe => {
    this.setState({ filteredCafe });
  };

  // Show the infowindow when a place is clicked
  handleInfoWindow = clickedCafe => {
    this.setState({ clickedPlace: clickedCafe });
    this.setState({ menuHidden: false });
  };

  render() {
    return (
      <div className="app" role="application" aria-label="map">
        <Header />
        <Map
          cafes={this.state.filteredCafe}
          clickedPlace={this.state.clickedPlace}
          handleInfoWindow={this.handleInfoWindow}
        />

        <SideBar
          cafes={this.state.cafes}
          handleInfoWindow={this.handleInfoWindow}
          updateList={this.updateList}
          menuHidden={this.state.menuHidden}
        />

        <Footer />
      </div>
    );
  }
}

export default App;

Sidebar1.js

import React, { Component } from "react";

class SideBar extends Component {
  state = {
    query: ""
  };

  //filter the cafes depending on the search
  refreshQuery = query => {
    this.setState({ query });
    this.props.updateList(this.filterCafes(this.props.cafes, query));
  };

  filterCafes = (cafes, query) => {
    if (!cafes) {
      return;
    }
    cafes.filter(cafe => cafe.name.toLowerCase().includes(query.toLowerCase()));
  };

  //cafes displayed in SideBar
  render() {
    const cafePlaces = this.props.cafes;
    const typedQuery = this.state.query;

    const listCafes =
      cafePlaces &&
      this.filterCafes(cafePlaces, typedQuery).map((cafe, idx) => {
        return (
          <li
            key={cafe.id}
            className="cafe"
            tabIndex={0}
            aria-label={cafe.name}
            onClick={() => {
              this.props.handleInfoWindow(idx);
            }}
            onKeyPress={() => {
              this.props.handleInfoWindow(idx);
            }}
          >
            {cafe.name}
          </li>
        );
      });

    return (
      <aside>
        <div className="sideBar">
          <div className="locations-list">
            <input
              type="text"
              placeholder="Search for a place"
              aria-label="Type to look for a cafe"
              value={this.state.query}
              onChange={e => this.refreshQuery(e.target.value)}
            />
            <ul aria-labelledby="Cafe list">{listCafes}</ul>
          </div>
        </div>
      </aside>
    );
  }
}

export default SideBar;

Places.js

import React, { Component } from "react";

import {
  withScriptjs,
  withGoogleMap,
  GoogleMap,
  Marker,
  InfoWindow
} from "react-google-maps";

class Map extends Component {
  render() {
    const places = this.props.cafes;
    const animatePlace = this.props.clickedPlace;

    /* create Google Map App and markers, infowindow from FourSquare API from https://github.com/tomchentw/react-google-maps/blob/master/src/docs/configuration.md 
and https://tomchentw.github.io/react-google-maps/#infowindow and https://github.com/tomchentw/react-google-maps/issues/753 */

    const style = {
      height: "100%"
    };

    const styleMap = {
      height: "600px",
      width: "100%"
    };

    //define map with markers and infowindow then return it below to display within container div
    const WMap = withScriptjs(
      withGoogleMap(props => (
        <GoogleMap
          defaultZoom={14}
          defaultCenter={{ lat: 51.656489, lng: -0.39032 }}
        >
          {places &&
            places.map((place, i) => (
              <Marker
                key={i}
                position={{ lat: place.location.lat, lng: place.location.lng }}
                id={place.id}
                name={place.name}
                onClick={() => {
                  this.props.handleInfoWindow(i);
                }}
                animation={
                  animatePlace === i ? window.google.maps.Animation.DROP : null
                }
              >
                {animatePlace === i && (
                  <InfoWindow onCloseClick={props.onToggleOpen}>
                    <div
                      className="infoWindow"
                      tabIndex={0}
                      aria-label="Infowindow"
                    >
                      <h2>{place.name}</h2>
                      <hr />

                      <p>
                        <strong>Address: </strong>
                        {place.location.formattedAddress[0]}
                      </p>
                      <p>{place.location.formattedAddress[1]}</p>
                      <p>{place.location.formattedAddress[2]}</p>
                      <p>{place.location.formattedAddress[3]}</p>
                      <p>{place.location.formattedAddress[4]}</p>
                    </div>
                  </InfoWindow>
                )}
              </Marker>
            ))}
        </GoogleMap>
      ))
    );

    return (
      <div className="map">
        <div className="wmap" role="application">
          <WMap
            googleMapURL="https://maps.googleapis.com/maps/api/js?key=AIzaSyCFk8F7SikfJihxgfeWargVEIsb31hwlwA&v=3.exp"
            loadingElement={<div style={style} />}
            containerElement={<div style={styleMap} />}
            mapElement={<div style={style} />}
          />
        </div>
      </div>
    );
  }
}

export default Map;