用户提交后,react-google-maps呈现标记

时间:2018-02-06 03:36:09

标签: javascript forms reactjs redux react-google-maps

React / Redux新手在这里。我有一个表单输入,允许用户输入医生问题。它通过Redux动作从服务器返回医生列表,并在地图上显示医生列表和每个医生位置的标记(react-google-maps)。

当我点击提交时,显示正确问题的医生列表,地图就在那里,但没有标记。我只能在提交表格后显示地图上的标记,然后点击列表中的医生显示他们的详细信息。

想要:输入医生问题,并在用户点击提交时在地图上呈现医生和标记列表。然后,选择医生查看他们的详细信息页面(这是另一个问题,路由到动态详细信息页面)。

我认为,我需要使用生命周期方法但不确定如何实现它。或者,有没有更好的方法来处理Redux?

医生组成部分:

import React, { Component } from 'react';
import PropTypes from 'prop-types';

import DoctorSearchForm from '../../containers/doctors/DoctorSearchForm';
import DoctorList from './DoctorList';
import Map from '../maps/Map';


class Doctors extends Component {

  constructor(props) {
    super(props);
    this.state = {
      markers: [],
      isMarkerShown: false
    }
  }

  componentDidMount() {
    this.getMarkers();
  }

  getMarkers = () => {
    let practices = this.props.doctors.map(function(doctor, index) {
      return {
        title: doctor.profile.first_name + ' ' + doctor.profile.last_name,
        location: {
          lat: doctor.practices[0].visit_address.lat,
          lng: doctor.practices[0].visit_address.lon
        }
      }
    });
    this.setState({ markers: practices, isMarkerShown: true });
  }

  render() {
    const { doctors, match } = this.props;

    return (
      <div>
        <DoctorSearchForm getMarkers={this.getMarkers} />
        <div className="row">
          <div className="col-md-4">
            <DoctorList doctors={doctors} match={match} />
          </div>
          <div className="col-md-8">
            <Map
              isMarkerShown={this.state.isMarkerShown}
              center={{ lat: 45.6318,lng: -122.6716 }}
              zoom={12}
              markers={this.state.markers}
              />
          </div>
        </div>
      </div>
    );
  }
}

Doctors.propTypes = {
  doctors: PropTypes.array.isRequired,
  match: PropTypes.object.isRequired
}

export default Doctors;

DoctorList组件:

import React from "react";
import { Route } from 'react-router-dom';

import DoctorItem from './DoctorItem';
import DoctorView from './DoctorView';


class DoctorList extends React.Component {
  render() {
    const { doctors, match } = this.props;
    const linkList = doctors.map((doctor, index) => {
      return (
        <DoctorItem doctor={doctor} match={match} key={index} />
      );
    });

    return (
      <div>
        <h3>DoctorList</h3>
        <ul>{linkList}</ul>
        <Route path={`${match.url}/:name`}
          render={ (props) => <DoctorView data= {this.props.doctors} {...props} />}
          />
        </div>
      );
  }
}

export default DoctorList;

DoctorItem组件:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Link, Route } from 'react-router-dom';

import DoctorView from './DoctorView';


const DoctorItem = (props) => {
  const { doctor, match } = props;
    return (
      <li>
        <Link to={{ pathname: `${match.url}/${doctor.profile.first_name}-${doctor.profile.last_name}` }}>
          {doctor.profile.first_name} {doctor.profile.last_name}
        </Link>
      </li>
    )
  }

  DoctorItem.propTypes = {
    doctor: PropTypes.object.isRequired,
  };

  export default DoctorItem;

DoctorView组件:

import React from 'react';


const DoctorView = ({ data, match }) => {
  const doctor = data.find(p => `${p.profile.first_name}-${p.profile.last_name}` === match.params.name);


  let doctorData;

  if (doctor) {
    const mappedSpecialties = Object.entries(doctor.specialties).map(([index, specialty]) => {
      return <li key={index} id={index}>{specialty.description}</li>;
      });
      doctorData =
      <div>
        <h5><strong>{doctor.profile.first_name} {doctor.profile.last_name}</strong> - {doctor.profile.title}</h5>
        <img src={doctor.profile.image_url} alt={"Dr." + doctor.profile.first_name + " " + doctor.profile.last_name} />
        <ul>{mappedSpecialties}</ul>
        <p>{doctor.profile.bio}</p>
      </div>;
    }
    return (
      <div>
        {doctorData}
      </div>
    )
  }

  export default DoctorView;

地图组件:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from 'react-google-maps';
import { compose, withProps } from "recompose";


export default Map = compose(
  withProps({
    googleMapURL:
      "https://maps.googleapis.com/maps/api/js?key={MY_KEY}&v=3.exp&libraries=geometry,drawing,places",
    loadingElement: <div style={{ height: `100%` }} />,
    containerElement: <div style={{ height: `400px` }} />,
    mapElement: <div style={{ height: `100%` }} />
  }),
  withScriptjs,
  withGoogleMap
)(props => (
  <GoogleMap defaultZoom={9} defaultCenter={{ lat: 45.6318,lng: -122.6716 }}>
    {props.markers.map((doctor, index) => {
          const marker = {
            position: { lat: doctor.location.lat, lng: doctor.location.lng },
            title: doctor.title
          }
          return <Marker key={index} {...marker} />;
        })}
  </GoogleMap>
));

我花了几天时间尝试寻找答案,但没有运气。任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

就像你在组件安装时计算标记一样,你需要在收到新道具时重新计算你的标记:

componentWillReceiveProps(nextProps) {
   this.getMarkers(nextProps);
}

这将要求您稍微更改getMarkers签名,以便它可以接受参数并在this.props操作中使用map而不是getMarkers = (props = this.props) => { let practices = props.doctors.map(function(doctor, index) { return { title: doctor.profile.first_name + ' ' + doctor.profile.last_name, location: { lat: doctor.practices[0].visit_address.lat, lng: doctor.practices[0].visit_address.lon } } }); this.setState({ markers: practices, isMarkerShown: true }); }

getMarkers()

假设您在DoctorSearchForm组件中呼叫render,您可以删除它,因为它会在接收新道具时自动更新标记 - 或者您可以完全绕过状态并在根据传入的props<ListView android:id="@id/android:list" android:layout_width="fill_parent" android:layout_height="wrap_content" android:drawSelectorOnTop="false" android:scrollbars="vertical"/> 中飞行。