score:1

Accepted answer

welcome to stackoverflow.

your problems can be alleviated by ensuring that cafes is set to null by default. then in sidebar1.js, i have added a truthy check to your filter that you used in the render method (cafeplaces && cafeplaces.filter...). this means that the filter will only be executed if cafeplaces was successfully fetched in your parent component, where you fetch the data.

you will also need to update places.js, as you use cafes in there too. i have also added an early return to the filtercafes method as it will error out when you try filtering as not cafes were loaded into the parent state if the api called failed.

(p.s. please note i broke your api call on purpose in the example code provided below).

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;


Related Query

More Query from same tag