Динамический рендеринг нескольких пользовательских маркеров с реакцией на собственные карты - PullRequest
0 голосов
/ 08 июня 2018

У меня есть серьезная проблема с производительностью при отображении маркеров на основе активных фильтров на карте.

У меня есть структура данных, которая выглядит примерно так:

const businesses = [
  {
    ...location,
    businessType: 'Market'
  },
  ...etc
]

В ней 150 элементовнабор данных прямо сейчас.Все маркеры отображаются по умолчанию.В настоящее время я генерирую данные для маркеров случайным образом.

Теперь у меня также есть категории, которые можно переключать, если категория переключается => отображать этот тип бизнеса.

Теперь всякий раз, когда яКатегории переключений Мой поток JS переходит на 0 кадров в секунду, и поток пользовательского интерфейса получает заблокированный.

Вот мой текущий код:

import React, { PureComponent } from 'react';
import { InteractionManager } from 'react-native';
import generateRandomMapData from 'utils/generateRandomMapData';
import CustomMarker from './CustomMarker';

const CENTER_OF_BERLIN = {
  latitude: 52.5200,
  longitude: 13.4050,
};

const RADIUS = 5000;
const AMOUNT_OF_MARKERS = 150;

class Markers extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      markers: null
    }
  }
  componentDidMount() {
    this.interactionHandle = InteractionManager.runAfterInteractions(() => {
      this.setState({ markers: generateRandomMapData(CENTER_OF_BERLIN, RADIUS, AMOUNT_OF_MARKERS) }, () => {
        this.interactionHandle = null;
      })
    })
  }
  componentWillUnmount() {
    if (this.interactionHandle) this.interactionHandle.cancel();
  }
  renderMarkers() {
    const { markers } = this.state;

    if (markers && markers.length) {
      return markers.map((b, i) => <CustomMarker location={b.location} key={i} businessType={b.businessType} />)
    }

    return null;
  }
  render() {
    return this.renderMarkers()
  }
}

export default Markers;

И файл для отдельных маркеров

import React, { PureComponent } from 'react';
import { View, InteractionManager } from 'react-native'
import { Marker } from 'react-native-maps';
import { connect } from 'react-redux';
import SVG from 'components/svg/SVG'

const BUSINESS_COLORS = {
  market: '#EC6D52',
  farm: '#763DAB',
  restaurant: '#C45D72',
  UrbanFarm: '#4B85DD',
  store: '#65A077',
}

class CustomMarker extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      shouldRender: false
    }
  }
  componentWillMount() {
    const { businessType, categories } = this.props;

    this.interactionHandle = InteractionManager.runAfterInteractions(() => {
      if (this._getActiveCategories(categories).includes(businessType) !== this.state.shouldRender) {
        this.setState({ shouldRender: this._getActiveCategories(categories).includes(businessType) }, () => {
          this.interactionHandle = null;
        });
      }
    });
  }
  componentDidUpdate() {
    if (this.interactionHandle) this.interactionHandle.cancel();

    const { businessType, categories } = this.props;
    const { shouldRender } = this.state;

    this.interactionHandle = InteractionManager.runAfterInteractions(() => {
      if (this._getActiveCategories(categories).includes(businessType) !== shouldRender) {
        this.setState({ shouldRender: this._getActiveCategories(categories).includes(businessType) }, () => {
          this.interactionHandle = null;
        })
      }
    });
  }
  componentWillUnmount() {
    if (this.interactionHandle) this.interactionHandle.cancel();
  }
  _getActiveCategories(categories) {
    const active = [];

    for (let category of categories) {
      if (category.active) {
        active.push(category.icon)
      }
    }

    return active;
  }
  render() {
    const { businessType, location } = this.props;
    const { shouldRender } = this.state;
    const iconColor = BUSINESS_COLORS[businessType.toLowerCase()];

    const opacity = shouldRender ? 1.0 : 0.0;

    return (
      <Marker coordinate={{ ...location }} opacity={opacity}>
        <View style={{ width: 29, height: 36 }}>
          <SVG icon="Marker" width="29" height="36" fill={iconColor} />
        </View>
      </Marker>
    );
  }
}

const mapStateToProps = (state) => ({
  categories: state.categories
});

export default connect(mapStateToProps, {
})(CustomMarker);

Сами категории живут в Redux, и маркеры отображаются на основе этого.

Кажется, что вызов setState на 25 затронутых одновременно маркеров невероятно тяжел, даже если используется InteractionManager.

Есть идеи, как оптимизировать эту производительность?

...