Почему несколько реактивных рендеров нарушают редактирование листовок и как это исправить?

Временное решение:

Лучший обходной путь, который я смог найти до сих пор - я оставлю это открытым на случай, если кто-то придумает что-то лучше. Две части:

  1. Назначьте ключ для очистки кеша, как в приведенном ниже обновлении (используйте UUID или что-то лучше, чем Math.random. Это устранит первоначальную проблему, но создаст новую проблему, заключающуюся в том, что последующие рендеры будут вызывать ошибки при редактировании. из уже не существующей геометрии.

  2. Исправьте эту второстепенную проблему, отслеживая режим редактирования и отключая рендеринг для компонента карты, возвращая shouldComponentUpdate false на время редактирования, примерно так:

    shouldComponentUpdate(){
        return !isEditingGeometry();
    }
    

Обновление:

Поскольку я опубликовал это, я начал работать с предположением, что это проблема жизненного цикла DOM/React. Это «решает» проблему самым глупым образом:

<Polygon key={Math.random()} positions={positions}/>

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


Вопрос:

У меня есть проект, в котором я пытаюсь использовать инструменты редактирования листовок в контексте реакции. Ниже приведен пример самой простой реализации этого, который отражает то, что я делаю. Если вы создадите новое приложение create-react-app и замените App.js этим кодом, вы можете запустить его и увидеть ошибку.

Что происходит: визуализируется карта, визуализируются фигуры. Если вы нажмете кнопку «редактировать», геометрии получат маркеры, и вы сможете их настроить. Все в порядке.

Если происходит последующий рендеринг (я имитирую это в образце кода, изменяя состояние с помощью таймера), то при нажатии кнопки «Редактировать» геометрия получает ручки, но не может быть скорректирована — двигаются только ручки. Отмена и повторное нажатие «редактировать» (перед другим рендерингом) позволяет вам редактировать фигуры.

Это сводит меня с ума - я наткнулся на несколько сообщений, которые указывают на общую проблему с рисованием листовок и редактированием полигонов после версии 4.12, но блокировка этой версии, похоже, не помогает ситуации (я просто получаю бонусное множество устаревших предупреждения).

Это ошибка в библиотеке или я делаю что-то глупое на стороне реакции, чего не вижу? Любые идеи или даже функциональные обходные пути принимаются с благодарностью.

Relevant lines from package.json: 
   "react": "^16.2.0", 
   "react-leaflet": "^1.8.0", 
   "react-leaflet-draw": "^0.18.0", 
   "leaflet": "^1.3.0", 
   "leaflet-draw": "^0.4.9",

import React, {Component} from 'react';

import './App.css';
import {
	Map,
	Circle,
	LayersControl,
	FeatureGroup,
	Polygon,
	TileLayer
} from 'react-leaflet';
import {EditControl} from "react-leaflet-draw"

class App extends Component {

	constructor(props) {
		super(props);
		this.state={
			thing:'stuff'
		}
	}

	componentDidMount(){
		// This is a demo hack just to force a second render
		setTimeout(() => {
			this.setState({thing:'otherstuff'});
		}, 2000);
	}

	render() {
		console.log("Render...");
    
    // Building geometries like this into an array and then in return 
    // mimics what my production code is doing, but I see the same problem 
    // if I put the geometry JSX inline below 
		let positions =[[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]];
		let tileServerURL='http://tile.stamen.com/watercolor/{z}/{x}/{y}.png';
		let editableGeometry = [];
		editableGeometry.push(<Circle key="circle" center={[37, -109.05]} radius={2000} />);
		editableGeometry.push(<Polygon key="polygon" positions={positions}/>);


		return (
			<div style={{width:'100vw',height:'100vh'}}>
			<Map ref='map' center={[37, -109.05]} zoom={13} className="ps_n3_mapComponent" style={{width:'100vw',height:'100vh'}}>
				<LayersControl position='topright'>
					<TileLayer key="tilelayer" url={tileServerURL}/>
					<FeatureGroup ref='editableFeaturegroup'>
						<EditControl/>
						{editableGeometry}
					</FeatureGroup>
				</LayersControl>
			</Map>
		</div>);
	}
}

export default App;


person andrew    schedule 08.09.2018    source источник
comment
Лучший обходной путь, который я смог найти до сих пор - я оставлю это открытым на случай, если кто-то придумает что-то лучше, но:   -  person andrew    schedule 10.09.2018


Ответы (3)


Я столкнулся с теми же проблемами при работе с React Leaflet. Я был достаточно разочарован, чтобы написать собственную реализацию листовки в качестве компонента реакции. Взгляните: https://github.com/Chris502/PureLeafletMap

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

* Изменить *
Это не ответ на актуальную проблему с react-leaflet и leaflet-draw. Это компонент карты, который позволит вам загружать функции/рисовать объекты geoJSON и редактировать их без использования логического значения Edit Mode или логики shouldComponentUpdate. Я получу рабочий пример.

person Chris Anderson    schedule 26.02.2019
comment
Спасибо за этот ответ. Не могли бы вы edit объяснить, как ваш компонент решает проблему, и краткое описание того, как вы бы использовали его? См. Приемлемо ли порекомендовать фреймворк или библиотеку в ответе? - person Cody Gray; 26.02.2019

У меня также были проблемы с тем, чтобы привлечь к сотрудничеству реактивную листовку. Я тоже был достаточно разочарован, чтобы реализовать форк здесь: https://github.com/andrewdodd/react-leaflet-draw

Основное разочарование, которое у меня было с react-leaflet-draw, заключалось в том, что он автоматически встраивает FeatureGroup внутрь элемента управления, который он использует для хранения фигур во время редактирования, но с которым вы не можете взаимодействовать или изменять. Это вызывает всевозможные проблемы при работе в стиле React (т. е. не в стиле leaflet.js, ориентированном на DOM), что, вероятно, вы и испытываете.

Чтение кода в моем форке, вероятно, убедит вас, что проще просто написать свою собственную оболочку (или скопировать файлы из моего форка в свой проект).

FWIW, «пример» на самом деле сложнее читать и понимать, чем саму библиотеку, так как пример должен иметь дело с сохранением состояния и т. д.

person Doddie    schedule 28.03.2019

Если вы используете функциональный компонент реакции, а координаты многоугольника берутся из реквизита. Вы должны использовать useEffect и useState, а когда реквизит изменяет перерисовку всего компонента.

const EditPolygon = ({ coordinates }: OwnProps) => {
  const [polygonData, setPolygonData] = useState()

  useEffect(() => {
    setPolygonData(coordinates)
  }, [coordinates]) 

return (
<FeatureGroup>
  <EditControl />
<Polygon positions={coordinates} key={some.id}>
</FeatureGroup>
)
person Viktor Barta    schedule 23.01.2020