外部元素悬停时触发标记,无需重新渲染地图React

时间:2018-08-10 12:21:53

标签: reactjs google-maps react-google-maps

我有一个类似于airbnb的应用,左侧有卡片,右侧有Google地图(使用react-google-maps包)

当用户将鼠标悬停在相应的卡片上时,我想突出显示(在下面的代码中通过动画显示)标记。

我实际上设法做到了(请参见下面的代码),但是问题是,当用户将另一张卡悬停在地图组件上时,地图组件会重新渲染。

有没有一种方法可以不必每次都重新渲染地图?

我的App.js(为理解目的而简化):

import React from "react";

import { Meals } from "../api/meals.js";
import { Restaurants } from "../api/restaurants.js";

import MealCard from "./MealCard";
import MealsMap from "./MealsMap";

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      highlightedMarker: ""
    };
    this.renderMeals = this.renderMeals.bind(this);
    this.highlightMarker = this.highlightMarker.bind(this);
  }

  renderMeals() {
    return this.props.meals.map(m => (
      <div
        className="col-sm-6 col-xs-12 "
        key={m._id}
        onMouseOver={() => this.highlightMarker(m.restaurant)}
      >
        <MealCard
          name={m.name}
          restaurant={
            this.props.restaurants.find(r => r._id === m.restaurant).name
          }
          image={m.image}
          address={
            this.props.restaurants.find(r => r._id === m.restaurant).address
          }
        />
      </div>
    ));
  }

  renderMap() {
    return (
      <MealsMap
        restaurants={this.props.restaurants}
        highlightedMarker={this.state.highlightedMarker}
      />
    );
  }

  highlightMarker(restaurantId) {
    this.setState({ highlightedMarker: restaurantId });
  }

  render() {
    return (
      <div>
        <div className="app-wrapper" style={{ display: "flex" }}>
          <div className="container">
            <div className="row">{this.renderMeals()}</div>
          </div>
          {this.renderMap()}
        </div>
      </div>
    );
  }
}

和我的MealsMap.js:

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

class MealsMap extends React.Component {
  render() {
    const GoogleMapMeals = withGoogleMap(props => (
      <GoogleMap
        defaultCenter={{ lat: 50.6320134, lng: 3.0568584 }}
        defaultZoom={13}
      >
        {this.props.restaurants.map(r => (
          <Marker
            key={r._id}
            position={{ lat: Number(r.lat), lng: Number(r.lng) }}
            animation={
              this.props.highlightedMarker === r._id
                ? google.maps.Animation.BOUNCE
                : ""
            }
          />
        ))}
      </GoogleMap>
    ));
    return (
      <GoogleMapMeals
        containerElement={
          <div
            style={{
              flex: "0 0 400px",
              height: "100vh",
              position: "sticky",
              top: "0"
            }}
          />
        }
        mapElement={
          <div
            style={{
              height: "100%",
              width: "100%",
              position: "absolute",
              top: "0px",
              left: "0px",
              backgroundColor: "rgb(229, 227, 223)"
            }}
          />
        }
      />
    );
  }
}
export default MealsMap;

1 个答案:

答案 0 :(得分:2)

您不想在GoogleMapMeals的render方法中定义MealsMap组件,因为这将导致每个渲染都有一个新组件,这将使React卸载上一个组件并创建一个全新的。

您可以改为在render方法之外定义GoogleMapMeals

示例

const GoogleMapMeals = withGoogleMap(props => (
  <GoogleMap
    defaultCenter={{ lat: 50.6320134, lng: 3.0568584 }}
    defaultZoom={13}
  >
    {props.markers.map(r => (
      <Marker
        key={r._id}
        position={{ lat: Number(r.lat), lng: Number(r.lng) }}
        animation={
          props.highlightedMarker === r._id
            ? google.maps.Animation.BOUNCE
            : ""
        }
      />
    ))}
  </GoogleMap>
));

class MealsMap extends React.Component {
  render() {
    return (
      <GoogleMapMeals
        markers={this.props.restaurants}
        highlightedMarker={this.props.highlightedMarker}
        containerElement={
          <div
            style={{
              flex: "0 0 400px",
              height: "100vh",
              position: "sticky",
              top: "0"
            }}
          />
        }
        mapElement={
          <div
            style={{
              height: "100%",
              width: "100%",
              position: "absolute",
              top: "0px",
              left: "0px",
              backgroundColor: "rgb(229, 227, 223)"
            }}
          />
        }
      />
    );
  }
}