Нежелательная ссылка на страницу sh с реакцией- google-maps - PullRequest
0 голосов
/ 09 мая 2020

Как сказано в заголовке, я получаю ненужную ссылку sh на страницу всякий раз, когда я перемещаю перетаскиваемый маркер. Я бы хотел настроить карту для панорамирования в новое положение маркера каждый раз, но на данный момент решу проблему с обновлением страницы sh.

Я добавил фрагменты кода, которые, как мне кажется, несут ответственность

Любая помощь приветствуется

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 };

1 Ответ

0 голосов
/ 10 мая 2020

Когда вы говорите «refre страницы» sh, вы имеете в виду, что страница в вашем браузере обновляется или просто компонент? Если это первый случай, я не знаю, как вам помочь. Однако у меня может быть ответ на последний вопрос.

Каждый раз, когда происходит изменение состояния в компоненте React, компонент будет повторно визуализироваться. Похоже, вы создаете новый экземпляр (const AsyncMap = ...) компонента GoogleMap при каждом рендеринге. Попробуйте сохранить AsyncMap перед функцией рендеринга, как указано в этом сообщении ( response- google-maps обновляет карту, когда выполняется onclick ).


Если это не сработает, это может быть что-то, что пакет делает независимо от React (я не знаком с пакетом, который вы используете.) В этом случае попробуйте добавить это перед функцией рендеринга.

shouldComponentUpdate(nextProps, nextState) {
  // Update in all cases EXCEPT when markerPosition changes
        if (nextState.markerPosition !==  this.state.markerPosition ) {
            return false;
        }
        return true;
      }
}

...