Как мне динамически обновлять коллекцию изображений MapMarker в зависимости от того, выбраны они или нет?

Недавно я был озадачен этим, и я хочу динамически обновлять изображения маркеров карты в зависимости от того, выбран ли маркер карты / активен или нет (каждый MapMarker имеет категорию, которая ссылается либо на активное изображение, либо на изображение по умолчанию из две коллекции изображений: InterestIcons и InterestIconsSelected. По сути, у меня есть коллекция MapMarkers, которые отображаются с отображением через коллекцию маркеров карты. Каждый MapMarker является дочерним компонентом MapView.Marker.

Я хотел бы отобразить все MapMarker в невыбранном / неактивном состоянии по умолчанию с изображением по умолчанию из InterestIcons, когда он выбран, это изображение MapMarker должно измениться на активное изображение из InterestIconsSelected, когда выбран другой MapMarker, предыдущий выбранный должен вернуться к изображению по умолчанию, а новое должно измениться на выбранное изображение.

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

MapScreen.js: отображает MapView для всех MapView.Marker MapMarkers через карту.

        <MapView
            ref={map => { this._map = map }}
            style={Styles.Map.map}
            initialRegion={this.props.region}
            onRegionChange={this.handleRegionChange}
        >
            {
                this.props.events
                    .filter(this.eventFilterTimeNearFuture)
                    .filter(this.eventFilterTimeNotPast)
                    .filter(this.eventFilterDistance)
                    .filter(this.eventFilterInterest)
                    .map(e =>
                        <MapView.Marker
                            key={e.id}
                            onPress={() => this.handleLocationPush(e)} // Set selected event state
                            coordinate={e.location}
                        >
                            <MapMarker
                                event={e}
                                size={this.state.markerSize}
                                selected={this.state.selectedEvent} // The selected event set by state call.
                            />
                        </MapView.Marker>
                    )
            }
            { !this.props.regionMock &&
                <MapView.Marker
                    key={'userLocation'}
                    coordinate={this.props.region}
                >
                    <MapMarker size={'user'} />
                </MapView.Marker>
            }
        </MapView>

MapMarker.js

import {interestIcons, interestColors, interestIconsSelected} from "../../utils/Icons";

import {Styles} from '../../StyleProvider';

class MapMarker extends React.Component {

constructor() {
    super();
    this.state = {
        initialized: false,
        active: false,
    };
};    

componentWillReceiveProps(nextProps) {
    if (!this.state.initialized) {
        console.log('initialization');            
        this.setState({initialized: true});
    }
    else {
        // If the nextProps.selected prop exists which it will
        if (nextProps.selected) {
            // If the nextProps.selected props id equals the this event id then selected else non-selected.
            if (nextProps.selected.id === nextProps.event.id) {
                console.log('SELECTED: ' + JSON.stringify(nextProps.selected));
                // set staae to active
                this.setState({
                    active: true
                });
                console.log(interestIconsSelected[nextProps.event.interest[0]]);
            } else {
                // set state to not active
                // console.log('NON-SELECTED: ' + JSON.stringify(nextProps.event));   
                this.setState({
                    active: false
                });                
            }
            this.forceUpdate();
        }
    }
}

 markerIcon(interest) {
    return this.state.active ? interestIconsSelected[interest] : interestIcons[interest];
 }

renderIcon() {
    if (this.props.event.type === 'Event') {
        return (
            <Image
                source={this.markerIcon(this.props.event.interest[0])}
                style={Styles.MapMarker.eventImage}
            />
        )
    }
}

КомпонентWillReceiveProps (nextProps) все еще находится в стадии разработки, и это указывает «достаточно хорошо» на текущее выбранное событие и все невыбранные события.

Я попытался установить источник изображения для использования, скажем, this.state.image, а затем установить состояние изображения в componentWillReceiveProps соответственно, т.е.

if (nextProps.selected) {
    // If the nextProps.selected props id equals the this event id then selected else non-selected.
    if (nextProps.selected.id === nextProps.event.id) {
        console.log('SELECTED: ' + JSON.stringify(nextProps.selected));
        // set staae to active
        this.setState({
            active: true,
            image: this.markerIcon(nextProps.event.interest[0], true)
        });
        console.log(interestIconsSelected[nextProps.event.interest[0]]);
    } else {
        // set state to not active
        console.log('NON-SELECTED: ' + JSON.stringify(nextProps.event));   
        this.setState({
            active: false,
            image: this.markerIcon(nextProps.event.interest[0], false)
        });                
    }
}

renderIcon() {
    if (this.props.event.type === 'Event') {
        return (
            <Image
                source={this.state.image}
                style={Styles.MapMarker.eventImage}
            />
        )
    }
}

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

Большое спасибо, ценю любую помощь.

Обновление: Попытка определить компонент изображения в MapView.Marker, и это не работает.

this.state.markers
.map(e =>
    <MapView.Marker
        key={e.id}
        onPress={() => this.handleLocationPush(e)}
        coordinate={e.location}
    >
        {/* <MapMarker
            event={e}
            size={this.state.markerSize}
        /> */}
        <Image
            source={this.state.selectedEvent === e ? interestIconsSelected[e.interest[0]] : interestIcons[e.interest[0]]}
            style={Styles.MapMarker.eventImage}
        />
    </MapView.Marker>
)

НО это работает, хотя вы, похоже, не можете применить стиль к MapView.Marker, но это не та реализация, которую я хотел бы, поскольку я хотел бы сохранить настраиваемый компонент MapMarker

this.state.markers
.map(e =>
    <MapView.Marker
        key={e.id}
        onPress={() => this.handleLocationPush(e)}
        coordinate={e.location}
        image={this.state.selectedEvent === e ? interestIconsSelected[e.interest[0]] : interestIcons[e.interest[0]]}
    />
)

Вышеупомянутые два фрагмента кода с использованием свойства изображения непосредственно в MapView.Marker или с компонентом изображения непосредственно в MapView.Marker не подходят для использования дочернего компонента MapMaper.


person Michael Stokes    schedule 19.09.2017    source источник


Ответы (1)


вы используете componentWillReceiveProps метод жизненного цикла, который не запускался при первом рендеринге, также вы используете this.state.initialized с false в состоянии constructor, поэтому вам потребуется дважды щелкнуть, чтобы сделать его активным

componentWillReceiveProps(nextProps) { // it did not run at first render
  if (!this.state.initialized) { // this.state.initialized with is false in constructor
    console.log('initialization');            
    this.setState({initialized: true});
  }
  .......
}

вы можете полностью удалить свой componentWillReceiveProps, если сделаете что-то вроде этого

markerIcon() { //did not get interest directly instead access it from props
  return this.props.selected.id === this.props.event.id ?
   interestIconsSelected[this.props.event.interest[0]] 
   : 
   interestIcons[this.props.event.interest[0]];
}

здесь вы сравниваете два объекта с идентичным сравнением, поскольку они глубокие, вы можете использовать что-то вроде этого вместо этого, чтобы не запутать babel подробнее

<Image
  // use this.state.selectedEvent.id  === e.id instead of this.state.selectedEvent  === e
  source={this.state.selectedEvent.id  === e.id  ? interestIconsSelected[e.interest[0]] : interestIcons[e.interest[0]]}
  style={Styles.MapMarker.eventImage}
 />

Надеюсь, это поможет, спасибо

person Mohamed Khalil    schedule 22.09.2017
comment
Спасибо за ответ Мохамед, пожалуйста, посмотрите мои правки. Кажется, что если вы используете опору изображения MapView.Marker, изображение изменяется динамически, но любой дочерний компонент этого не делает даже при наличии такого условия, как `this.props.selected.id === this.props.event .я бы ? InterestIconsSelected [this.props.event.interest [0]]: InterestIcons [this.props.event.interest [0]]; - person Michael Stokes; 23.09.2017
comment
Можете ли вы создать быстрое репо для этого, также вы уверены, что это не проблема стиля, как не нажатый маркер? - person Mohamed Khalil; 23.09.2017