当openlayer中选定的功能发生变化时,React设置useState不起作用

问题描述 投票:0回答:1

我正在使用开放层构建这个 React 应用程序,但我遇到了 setState 问题。

我将解释这两个相关组件的工作原理:

MapWrapper:包裹开放图层地图的组件。其中有一个侦听器,每次鼠标光标移动时都会检查并将在该屏幕像素中找到的功能发送到父组件 (OlMap.js),如果那里没有任何功能,则将其发送到 null。

这是听众:

initialMap.on('pointermove', function (e) {
  let newSelectedFeature = null

  initialMap.forEachFeatureAtPixel(e.pixel, function (f) {
    newSelectedFeature = f;
    console.log("HOVER", newSelectedFeature)
    return true;
  });
  
  props.onHoverFeature(newSelectedFeature)
});

这是完整的组件:

// react
import React, { useState, useEffect, useRef } from 'react';

// openlayers
import Map from 'ol/Map'
import View from 'ol/View'
import TileLayer from 'ol/layer/Tile'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import XYZ from 'ol/source/XYZ'
import {transform} from 'ol/proj'
import {toStringXY} from 'ol/coordinate';
import OSM, {ATTRIBUTION} from 'ol/source/OSM.js';

//css
import "./MapStyle.css"
import { Feature } from 'ol';
import { Point } from 'ol/geom';
import Style from 'ol/style/Style';
import Icon from 'ol/style/Icon';

function MapWrapper(props) {

  // set intial state
  const [ map, setMap ] = useState()
  const [ featuresLayer, setFeaturesLayer ] = useState()
  const [ selectedCoord , setSelectedCoord ] = useState()

  const [ selectedFeature, setSelectedFeature ] = useState(null)

  // pull refs
  const mapElement = useRef()
  
  // create state ref that can be accessed in OpenLayers onclick callback function
  //  https://stackoverflow.com/a/60643670
  const mapRef = useRef()
  mapRef.current = map

  const highlightStyle = new Style({
    image: new Icon({
      src: "https://i.imgur.com/gbfpoiQ.png",
      //src: "file:\\\\assets\\icons\\badMarker.png",
      anchor: [0.5, 1]
    })
  })

  const markerStandardStyle = new Style({
    image: new Icon({
      src: "https://i.imgur.com/GJ8XUQ7.png",
      //src: "file:\\\\assets\\icons\\badMarker.png",
      anchor: [0.5, 1]
    })
  })

  const changeSelectedFeature = (f) => {
    setSelectedFeature(f)
  }

  // initialize map on first render - logic formerly put into componentDidMount
  useEffect( () => {

    // create and add vector source layer
    const initalFeaturesLayer = new VectorLayer({
      source: new VectorSource(),
      style: markerStandardStyle
    })

    // create map
    const initialMap = new Map({
      target: mapElement.current,
      layers: [
        new TileLayer({
            source: new OSM(),
        }),
        initalFeaturesLayer        
      ],
      view: new View({
        projection: 'EPSG:3857',
        center: [1877145.5647310177, 5030935.7155071795],
        zoom: 14
      }),
      controls: []
    })

    // set map onclick handler
    initialMap.on('click', handleMapClick)

    initialMap.on('pointermove', function (e) {
      let newSelectedFeature = null
    
      initialMap.forEachFeatureAtPixel(e.pixel, function (f) {
        newSelectedFeature = f;
        console.log("HOVER", newSelectedFeature)
        return true;
      });
      
      props.onHoverFeature(newSelectedFeature)
    });

    // save map and vector layer references to state
    setMap(initialMap)
    setFeaturesLayer(initalFeaturesLayer)

  },[])

  // update map if features prop changes - logic formerly put into componentDidUpdate
  useEffect( () => {

    if (props.features.length) { // may be null on first render

      // set features to map
      featuresLayer.setSource(
        new VectorSource({
          features: props.features // make sure features is an array
        })
      )

      // // fit map to feature extent (with 100px of padding)
      // map.getView().fit(featuresLayer.getSource().getExtent(), {
      //   padding: [100,100,100,100]
      // })

    }

  },[props.features])

  // map click handler
  const handleMapClick = (event) => {

    // get clicked coordinate using mapRef to access current React state inside OpenLayers callback
    //  https://stackoverflow.com/a/60643670
    const clickedCoord = mapRef.current.getCoordinateFromPixel(event.pixel);

    console.log(clickedCoord)
    props.onClickMap(clickedCoord)

    // transform coord to EPSG 4326 standard Lat Long
    const transormedCoord = transform(clickedCoord, 'EPSG:3857', 'EPSG:4326')

    // set React state
    setSelectedCoord( transormedCoord )

    console.log(transormedCoord)
    
  }

  // render component
  return (      
    <div ref={mapElement} className="map-container"></div>
  ) 

}

export default MapWrapper

OlMap:这是父组件。它在函数 onHoverFeature 中接收找到的特征;那么如果它与之前找到的功能不同,则应该将其设置为状态,但 setSelectedFeature 被调用但不起作用

import React, { useEffect, useState } from 'react'
import MapWrapper from './MapWrapper'
import MapSearchBar from './MapSearchBar'
import SideSlider from './components/SideSlider'

import { Feature } from 'ol';
import { Point } from 'ol/geom';
import Style from 'ol/style/Style';
import Icon from 'ol/style/Icon';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';

export default function OlMap(props) {

    const [showRightSlider, setShowRightSlider] = useState(true)
    const [coordsToShow, setCoordsToShow] = useState([0,0])
    const [features, setFeatures] = useState([])
    const [selectedFeature, setSelectedFeature] = useState(null)

    const highlightStyle = new Style({
        image: new Icon({
          src: "https://i.imgur.com/gbfpoiQ.png",
          //src: "file:\\\\assets\\icons\\badMarker.png",
          anchor: [0.5, 1]
        })
      })

    const onClickMap = (coord) => {
        setShowRightSlider(true);
        setCoordsToShow(coord)
        createMarker("TEST", coord)
    }

    const onHoverFeature = (f) => {
        if(f?.ol_uid === selectedFeature?.ol_uid) {
            return
        }
        if(selectedFeature) {
            selectedFeature.setStyle(undefined)
        }
        if(f){
            f.setStyle(highlightStyle)
        }
        setSelectedFeature(f)
    }

    let idFeature = 0

    //create marker
    const createMarker = (name, coord) => {
        console.log(name, coord)

          const marker =  new Feature({
             geometry:  new Point(coord),
             name: name,
             id: idFeature++
          })

        setFeatures(oldFeature =>  [...oldFeature, marker])
    }

    return(
        <div style={{height: "90%", width: "100%", backgroundColor: "yellow", position: "relative"}}>
            <SideSlider show={showRightSlider} coord={coordsToShow} onClose={() => {setShowRightSlider(false)}}></SideSlider>
            <MapSearchBar></MapSearchBar>
            <MapWrapper features={features} onClickMap={onClickMap} onHoverFeature={onHoverFeature} /*selectedFeature={selectedFeature}*/ />
        </div>
    )
}
javascript reactjs openlayers
1个回答
0
投票

我还在 React 项目中实现了功能选择。而且我在您的代码中没有看到添加“选择”交互。

const selectRef = useRef<Select>(
        new Select({
            style: null,
            multi: false,
        })
    );

    map!.addInteraction(selectRef.current);
© www.soinside.com 2019 - 2024. All rights reserved.