如何根据是否选择动态更新MapMarker图像的集合?

Mic*_*kes 8 reactjs react-native airbnb-js-styleguide react-native-maps

最近我一直对此感到困惑,我希望根据是否选择/激活地图标记来动态更新地图标记图像(每个MapMarker都有一个类别引用活动图像或默认图像来自两个图像集合:interestIcons和interestIconsSelected.基本上我有一个MapMarkers集合,它们通过map标记集合进行映射.每个MapMarker都是MapView.Marker的子组件.

我想将所有MapMarkers渲染为默认的非选择/非活动状态,其中包含来自interestIcons的默认图像,当选中时,MapMarker图像应该从interestIconsSelected更改为活动图像,当选择另一个MapMarker时,之前选择的应该是恢复为默认图像,新的应更改为所选图像.

目前,我能够使用默认图像渲染地图标记,但是当选择地图标记时,图像似乎不会立即更改,除非您再次缩小/放大,即导致某种重新渲染,我想这样点击MapMarker会立即导致图像更新.

MapScreen.js: 通过地图渲染所有MapView.Marker MapMarkers的MapView.

        <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>
Run Code Online (Sandbox Code Playgroud)

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}
            />
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

componentWillReceiveProps(nextProps)仍然是正在进行的工作,它表示当前所选事件和非选定事件的"足够好".

我试图将图像源设置为使用say 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}
            />
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

更改图像状态似乎确实更有效,因为图像会立即更改,但似乎初始渲染中的图像根本不会被设置,因此它将只是一个空图标,直到被选中.

非常感谢,感谢任何帮助.

更新:尝试在MapView.Marker下定义Image组件,但这不起作用.

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>
)
Run Code Online (Sandbox Code Playgroud)

但是这可行,虽然您似乎无法将样式应用于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]]}
    />
)
Run Code Online (Sandbox Code Playgroud)

以上两个代码的snipets使用MapView.Marker上的image prop或者直接在MapView.Marker下使用Image组件并不像使用MapMaper子组件那样好.

Moh*_*lil 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});
  }
  .......
}
Run Code Online (Sandbox Code Playgroud)

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]];
}
Run Code Online (Sandbox Code Playgroud)

在这里,您比较两个具有相同比较的对象,因为它们很深,您可以使用类似这样的东西,而不是让 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}
 />
Run Code Online (Sandbox Code Playgroud)

我希望有帮助谢谢