ReactJS - 如何检查值是否未定义?

问题描述 投票:0回答:1

我正在使用Google Places API创建一个查找最近的餐厅应用。我在我的ResultItem组件的一个道具中调用背景图片。<ResultsItem name={places.name} image={Thumbnail} rating={places.rating} rating_total={places.user_ratings_total} />

这张图片在这部分代码上面的const中被定义为Thumbnail。我的代码运行得很顺利,但是一旦 places.photos[0] 返回 undefined (意味着这是 Google Place 没有上传任何图片),我就会得到一个错误说。

Unhandled Rejection (TypeError): 无法读取未定义的属性'0'。

我想我要做的是检查 places.photos[0]是否未定义,但我似乎没有得到正确的答案......。

我的目标是当这个值未定义时,显示另一个占位符图片,如果它被定义了,组件应该从google places api中获取图片。如果它被定义了,组件应该从google places api中获取图片。

谁能帮帮我?

FULL COMPONENT:

import React, { Component } from 'react';

// Imports
import axios from 'axios';
import Script from 'react-load-script';
import Placeholder from './Placeholder.jsx';
import FadeIn from 'react-fade-in';
import {
  Spinner,
  Paragraph,
  SideSheet,
  Tooltip,
  IconButton,
  SearchInput
} from 'evergreen-ui';
import ResultsItem from '../../components/ResultsItem/ResultsItem.jsx';

import Geocode from 'react-geocode';

// Styles
import './Search.scss';

class Autocomplete extends Component {
  // Define Constructor
  constructor(props) {
    super(props);

    // Declare State
    this.state = {
      type: 'restaurant',
      radius: 10,
      lat: '59.0738',
      lng: '41.3226',
      city: '',
      query: '',
      open: false,
      places: [],
      place_detail: [],
      sidebar: false,
      loading: true
    };

    this.currentLocationOnClick = this.currentLocationOnClick.bind(this);
    this.handlePlaceSelect = this.handlePlaceSelect.bind(this);
  }

  currentLocationOnClick = async () => {
    let { lat, lng, places } = this.state;
    const URL = `https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${lat},${lng}&type=restaurant&radius=${5 *
      1000}&key=MY_API_KEY`;
    navigator.geolocation.getCurrentPosition(
      async position => {
        this.setState({ lat: position.coords.latitude });
        this.setState({ lng: position.coords.longitude });

        const URL = `https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${
          position.coords.latitude
        },${position.coords.longitude}&type=restaurant&radius=${5 *
          1000}&key=MY_API_KEY`;

        const response = await axios.get(URL);
        console.log(response.data);
        places = response.data.results;
        this.setState({ places });
      },
      error => {
        console.log('Error getting location');
      }
    );
  };

  async componentDidMount() {
    const url = `https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=
    ${this.state.lat},${this.state.lng}type=restaurant&radius=${2 *
      1000}&key=MY_API_KEYE`;
    const response = await fetch(url);
    const data = await response.json();
    this.setState({ places: data.results });
    console.log(data.results);
  }

  handleScriptLoad = () => {
    // Declare Options For Autocomplete
    const options = {
      types: ['address']
    }; // To disable any eslint 'google not defined' errors

    // Initialize Google Autocomplete
    /*global google*/ this.autocomplete = new google.maps.places.Autocomplete(
      document.getElementById('autocomplete'),
      options
    );

    // Avoid paying for data that you don't need by restricting the set of
    // place fields that are returned to just the address components and formatted
    // address.
    this.autocomplete.setFields(['address_components', 'formatted_address']);

    // Fire Event when a suggested name is selected
    this.autocomplete.addListener('place_changed', this.handlePlaceSelect);
  };

  handlePlaceSelect = async () => {
    let { query, lat, lng } = this.state;

    this.setState({ loading: true });

    // Extract City From Address Object
    const addressObject = this.autocomplete.getPlace();
    const address = addressObject.address_components;

    Geocode.setApiKey('MY_API_KEY');

    // Check if address is valid
    let city;
    if (address) {
      city = address[0].long_name;
      query = addressObject.formatted_address;
    }

    try {
      const response = await Geocode.fromAddress(query);
      ({ lat, lng } = response.results[0].geometry.location);
    } catch (error) {
      console.error(error);
    }

    let places;
    try {
      const URL = `https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${lat},${lng}&type=restaurant&radius=${5 *
        1000}&key=MY_API_KEY`;
      const response = await axios.get(URL);
      console.log(response.data);
      places = response.data.results;
    } catch (error) {
      console.log(error.message);
    }

    this.setState({ query, places, city, lat, lng });
    setTimeout(() => this.setState({ loading: false }), 400);
  };

  render() {
    const { loading } = this.state;

    return (
      <div>
        <div className="flex align-center">
          <div className="search">
            <SearchInput
              id="autocomplete"
              placeholder="Search by address"
              width="100%"
              height={56}
            />
            <Script
              url="https://maps.googleapis.com/maps/api/js?key=MY_API_KEY&libraries=places,geometry&callback=initAutocomplete"
              onLoad={this.handleScriptLoad}
            />
          </div>

          <div className="current-location">
            <Tooltip content="Use current location">
              <IconButton
                icon="locate"
                iconSize={16}
                height={32}
                onClick={this.currentLocationOnClick}
              >
                {this.state.lat} & {this.state.lng}
              </IconButton>
            </Tooltip>
          </div>
        </div>

        <div className="results">
          {this.state.places.map(places => {
            const Thumbnail = `https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=${places.photos[0].photo_reference}&key=MY_API_KEY
    `;
            return (
              <div
                className="results-flex"
                onClick={async () => {
                  let loading;
                  let sidebar;
                  let place_detail;
                  try {
                    const URL = `https://maps.googleapis.com/maps/api/place/details/json?place_id=${places.place_id}&fields=name,rating,formatted_phone_number&key=
                    MY_API_KEY`;
                    const response = await axios.get(URL);
                    console.log(response.data);
                    place_detail = response.data.result;
                  } catch (error) {
                    console.log(error.message);
                  }

                  this.setState(
                    { place_detail, sidebar: true }
                    // () => this.props.sideBarOpen()
                  );
                }}
              >
                {this.state.loading ? (
                  <>
                    <div className="flex justify-center">
                      <Placeholder />
                    </div>
                  </>
                ) : (
                  <FadeIn>
                    <ResultsItem
                      name={places.name}
                      image={Thumbnail}
                      rating={places.rating}
                      rating_total={places.user_ratings_total}
                    />
                  </FadeIn>
                )}
              </div>
            );
          })}

          <SideSheet
            isShown={this.state.sidebar}
            onCloseComplete={() => this.setState({ sidebar: false })}
          >
            <Paragraph margin={40}>{this.state.place_detail.name}</Paragraph>
          </SideSheet>
        </div>
      </div>
    );
  }
}

export default Autocomplete;
reactjs
1个回答
2
投票

我认为最好的解决办法是把它分配给一个变量。

 const photoReference = places && places.photos[0] ? places.photos[0].photo_reference : placeholder;

0
投票

试着用if else来处理它

例如

if(!!places.photos[0]) {   
const Thumbnail =
`https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=${places.photos[0].photo_reference}&key=MY_API_KEY
}
else { const Thumbnail = `another image url` }
© www.soinside.com 2019 - 2024. All rights reserved.