使用react-google-maps刷新不需要的页面。
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用react-google-maps刷新不需要的页面。相关的知识,希望对你有一定的参考价值。
正如标题所说,每当我移动可拖动的标记时,我都会得到一个不必要的页面刷新。我想设置地图每次都平移到新的标记位置,但目前只能解决页面刷新的问题。
我已经添加了一些代码片段,我认为是这些代码造成的。
不胜感激
import React, { Component } from 'react';
import { withGoogleMap, GoogleMap, withScriptjs, InfoWindow, Marker } from "react-google-maps";
import { Mutation } from 'react-apollo';
import gql from 'graphql-tag';
import Geocode from "react-geocode";
import User from './User';
import Autocomplete from 'react-google-autocomplete';
import FormBlock from './styles/FormBlock'
import SickButton from './styles/SickButton';
import styled from 'styled-components';
import Form from './styles/Form';
import Error from './ErrorMessage';
import Router from 'next/router';
Geocode.setApiKey( "AIzaSyC7oaBUKbAULgrhMSPx-pT8zr2PG3lpOT4" );
Geocode.enableDebug();
const Mapbox = styled.div`
margin: 0;
padding: 10px;
z-index: 3;
`;
const CREATE_JOB_MUTATION = gql`
mutation CREATE_JOB_MUTATION(
$address: String!
$lat: Float
$lng: Float
$description: String!
$image: String!
$cube: Int!
$reqPickup: String
$instructions: String!
$feedback: String
$pickup: DateTime
$charges: Int
$price: Int
) {
createJob(
address: $address
lat: $lat
lng: $lng
description: $description
image: $image
cube: $cube
reqPickup: $reqPickup
instructions: $instructions
feedback: $feedback
pickup: $pickup
charges: $charges
price: $price
) {
id
address
lat
lng
}
}
`;
class Map extends Component{
constructor( props ){
super( props );
this.state = {
address: '',
lat: '',
lng: '',
city: '',
area: '',
state: '',
image: '',
cube: '',
reqPickup: '',
instructions: '',
feedback: '',
pickup: '',
charges: '0',
price: '0',
mapPosition: {
lat: this.props.center.lat,
lng: this.props.center.lng
},
markerPosition: {
lat: this.props.center.lat,
lng: this.props.center.lng
}
};
this.onPlaceSelected = this.onPlaceSelected.bind(this);
}
handleChange = (e) => {
const { name, type, value } = e.target;
const val = type === 'number' ? parseFloat(value) : value;
this.setState({ [name]: val});
};
uploadFile = async e => {
const files = e.target.files;
const data = new FormData();
data.append('file', files[0]);
data.append('upload_preset', 'sickfits');
const res = await fetch('https://api.cloudinary.com/v1_1/wesbostutorial/image/upload', {
method: 'POST',
body: data,
});
const file = await res.json();
this.setState({
image: file.secure_url,
largeImage: file.eager[0].secure_url,
});
};
/**
* Get the current address from the default map position and set those values in the state
*/
componentDidMount() {
Geocode.fromLatLng( this.state.mapPosition.lat , this.state.mapPosition.lng ).then(
response => {
const address = response.results[0].formatted_address,
addressArray = response.results[0].address_components,
city = this.getCity( addressArray ),
area = this.getArea( addressArray ),
state = this.getState( addressArray );
// console.log( 'city', city, area, state );
this.setState( {
address: ( address ) ? address : '',
area: ( area ) ? area : '',
city: ( city ) ? city : '',
state: ( state ) ? state : '',
lat: this.state.markerPosition.lat,
lng: this.state.markerPosition.lng,
} )
},
error => {
console.error( error );
}
);
};
getCity = ( addressArray ) => {
let city = '';
for( let i = 0; i < addressArray.length; i++ ) {
if ( addressArray[ i ].types[0] && 'administrative_area_level_2' === addressArray[ i ].types[0] ) {
city = addressArray[ i ].long_name;
return city;
}
}
};
/**
* Get the area and set the area input value to the one selected
*
* @param addressArray
* @return {string}
*/
getArea = ( addressArray ) => {
let area = '';
for( let i = 0; i < addressArray.length; i++ ) {
if ( addressArray[ i ].types[0] ) {
for ( let j = 0; j < addressArray[ i ].types.length; j++ ) {
if ( 'sublocality_level_1' === addressArray[ i ].types[j] || 'locality' === addressArray[ i ].types[j] ) {
area = addressArray[ i ].long_name;
return area;
}
}
}
}
};
/**
* Get the address and set the address input value to the one selected
*
* @param addressArray
* @return {string}
*/
getState = ( addressArray ) => {
let state = '';
for( let i = 0; i < addressArray.length; i++ ) {
for( let i = 0; i < addressArray.length; i++ ) {
if ( addressArray[ i ].types[0] && 'administrative_area_level_1' === addressArray[ i ].types[0] ) {
state = addressArray[ i ].long_name;
return state;
}
}
}
};
/**
* And function for city,state and address input
* @param event
*/
/**
* This Event triggers when the marker window is closed
*
* @param event
*/
onInfoWindowClose = ( event ) => {
};
/**
* When the marker is dragged you get the lat and long using the functions available from event object.
* Use geocode to get the address, city, area and state from the lat and lng positions.
* And then set those values in the state.
*
* @param event
*/
onMarkerDragEnd = ( event ) => {
let newLat = event.latLng.lat(),
newLng = event.latLng.lng();
Geocode.fromLatLng( newLat , newLng ).then(
response => {
const address = response.results[0].formatted_address,
addressArray = response.results[0].address_components,
city = this.getCity( addressArray ),
area = this.getArea( addressArray ),
state = this.getState( addressArray );
this.setState( {
address: ( address ) ? address : '',
area: ( area ) ? area : '',
city: ( city ) ? city : '',
state: ( state ) ? state : '',
lat: this.state.markerPosition.lat,
lng: this.state.markerPosition.lng,
markerPosition: {
lat: newLat,
lng: newLng
},
mapPosition: {
lat: newLat,
lng: newLng
},
} )
},
error => {
console.error(error);
}
);
};
/**
* When the user types an address in the search box
* @param place
*/
onPlaceSelected = ( place ) => {
// console.log( 'plc', place );
const address = place.formatted_address,
addressArray = place.address_components,
city = this.getCity( addressArray ),
area = this.getArea( addressArray ),
state = this.getState( addressArray ),
latValue = place.geometry.location.lat(),
lngValue = place.geometry.location.lng();
// Set these values in the state.
this.setState({
address: ( address ) ? address : '',
area: ( area ) ? area : '',
city: ( city ) ? city : '',
state: ( state ) ? state : '',
lat: this.state.markerPosition.lat,
lng: this.state.markerPosition.lng,
markerPosition: {
lat: latValue,
lng: lngValue
},
mapPosition: {
lat: latValue,
lng: lngValue
},
})
};
render(){
const defaultMapOptions = {
disableDefaultUI: true,
};
const AsyncMap = withScriptjs(
withGoogleMap(
props => (
<GoogleMap
google={ this.props.google }
defaultZoom={ this.props.zoom }
defaultCenter={{ lat: this.state.mapPosition.lat, lng: this.state.mapPosition.lng }}
defaultOptions={defaultMapOptions}
>
<Marker google={this.props.google}
name={''}
draggable={true}
onDragEnd={ this.onMarkerDragEnd }
position={{ lat: this.state.markerPosition.lat, lng: this.state.markerPosition.lng }}
/>
<Marker />
</GoogleMap>
)
)
);
let map;
if( this.props.center.lat !== undefined ) {
map = <Mapbox>
<AsyncMap
googleMapURL="https://maps.googleapis.com/maps/api/js?key=AIzaSyC7oaBUKbAULgrhMSPx-pT8zr2PG3lpOT4&libraries=places"
loadingElement={
<div style={{ height: `100%` }} />
}
containerElement={
<div style={{ height: this.props.height, margin: '0px', padding: 'auto',}} />
}
mapElement={
<div style={{ height: `100%`, margin: '0px' }} />
}
/>
<Mutation mutation={CREATE_JOB_MUTATION} variables={this.state}>
{(createJob, { loading, error }) => (
<Form
data-test="form"
onSubmit={async e => {
// Stop the form from submitting
e.preventDefault();
// call the mutation
this.setState({ address: this.state.address, lat: this.state.markerPosition.lat, lng: this.state.markerPosition.lng });
console.log(this.state);
const res = await createJob();
// change them to the single job page
Router.push({
pathname: '/orderprocess',
query: { id: res.data.createJob.id },
});
}}>
<Error error={error} />
<fieldset disabled={loading} aria-busy={loading}>
<label htmlFor="address">
<input
type="text"
id="address"
name="address"
placeholder="address"
required
readOnly value={this.state.address}
onChange={this.handleChange}
/>
</label>
<label htmlFor="lat">
<input
type="number"
id="lat"
name="lat"
placeholder="lat"
required
readOnly value={ this.state.markerPosition.lat}
onChange={this.handleChange}
/>
</label>
<label htmlFor="lng">
<input
type="number"
id="lng"
name="lng"
placeholder="lng"
required
readOnly value={this.state.markerPosition.lng}
onChange={this.handleChange}
/>
</label>
{/* <label htmlFor="description">
Describe your waste: Just a few words to describe the materials.
<input
type="text"
id="description"
name="description"
placeholder="eg: wood, bricks, old kitchen tops and a fridge"
required
value={this.state.description}
onChange={this.handleChange}
/>
</label>
<label htmlFor="image" className="pic">
Image: make sure you get it all in shot from a couple of different angles.
<input
type="file"
id="image"
name="image"
placeholder="Upload an image"
required
onChange={this.uploadFile}
/>
{this.state.image && (
<img width="200" src={this.state.image} alt="Upload Preview" />
)}
</label>
<label htmlFor="cube">
Cube: Have a a guess at cm3 of your waste. Don't worry if you get it wrong, its just to help us quote you accuratly.
<input
type="number"
id="cube"
name="cube"
placeholder="Estimate how many cubic metres your waste occupies"
required
value={this.state.cube}
onChange={this.handleChange}
/>
</label>
<label htmlFor="reqPickup">
Required Pickup: Tell us an ideal time to collect/deliver.
<input
type="text"
id="reqPickup"
name="reqPickup"
placeholder="eg: asap "
required
value={this.state.reqPickup}
onChange={this.handleChange}
/>
</label>
<label htmlFor="instructions">
Instructions: Any specific instructions such as desired collection time or access info.
<input
type="text"
id="instructions"
name="instructions"
placeholder="Instructions for the collection team"
required
value={this.state.instructions}
onChange={this.handleChange}
/>
</label> */}
<p
style={{
textAlign: 'center',
}}
>Submit your order and we'll come back to you in just a few moments with a quote and collection time options</p>
<div
style={{
display: 'flex',
margin: 'auto',
justifyContent: 'center',
}}
>
<button
type="submit">SUBMIT</button>
</div>
</fieldset>
</Form>
)}
</Mutation>
</Mapbox>
} else {
map = <div style={{height: this.props.height}} />
}
return( map )
}
}
export default Map
export { CREATE_JOB_MUTATION };
答案
当你说页面刷新时,你是指浏览器中的页面在刷新,还是仅仅是组件在刷新?如果是前一种情况,我不知道如何帮助你。不过,对于后者,我可能有一个答案。
每当React组件中的状态发生变化时,该组件就会重新渲染.React组件的状态。看起来你在每次渲染时都要创建一个新的GoogleMap组件实例(const AsyncMap =...)。试着在渲染函数之前存储AsyncMap,就像这个帖子一样(当点击时,react-google-maps正在刷新地图。).
如果这样不行,可能是该包独立于React做的事情(我不熟悉你使用的包。)在这种情况下,试着在你的渲染函数之前添加这个。
shouldComponentUpdate(nextProps, nextState) {
// Update in all cases EXCEPT when markerPosition changes
if (nextState.markerPosition !== this.state.markerPosition ) {
return false;
}
return true;
}
}
以上是关于使用react-google-maps刷新不需要的页面。的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 react-google-maps 通过单击在地图上添加标记?
如何将自定义按钮添加到 react-google-maps?