每当地图标记发生变化时,我想计算并更新地图的区域。所以我试图从地图的标记创建一个observable并订阅它:
class Map extends Component {
componentDidMount() {
const { store } = this.context
this.unsubscribe = store.subscribe(() => { })
const markers$ = Observable.from(this.props.markers)
markers$.subscribe(x => console.log('observable', x))
}
最初我只是控制台。记录标记 - 但最终我会想要在标记发生变化时运行getRegionForCoordinates
然后this.props.updateRegion
。什么都没有登录到控制台。我究竟做错了什么? this.props.markers
最初是一个空数组。
Map.js
import { StyleSheet } from 'react-native'
import React, { Component } from 'react'
import MapView from 'react-native-maps'
import { connect } from 'react-redux'
import {
Button,
Container
} from 'native-base'
import { Observable } from 'rxjs'
import selectMarkers from './markers.selector'
import { updateRegion } from './map.action'
import Icon from 'react-native-vector-icons/FontAwesome'
import { toggleMenu } from '../search-page/searchPage.action'
import mapStyle from './style'
const mapStateToProps = (state) => ({
region: state.get('map').get('region'),
markers: selectMarkers(state)
})
const mapDispatchToProps = (dispatch) => ({
onRegionChange: (region) => {
dispatch(updateRegion(region))
},
onToggleMenuClick: () => {
dispatch(toggleMenu())
}
})
const getRegionForCoordinates = (points) => {
// points should be an array of { latitude: X, longitude: Y }
let minX, maxX, minY, maxY;
// init first point
((point) => {
minX = point.latitude
maxX = point.latitude
minY = point.longitude
maxY = point.longitude
})(points[0])
// calculate rect
points.map((point) => {
minX = Math.min(minX, point.latitude)
maxX = Math.max(maxX, point.latitude)
minY = Math.min(minY, point.longitude)
maxY = Math.max(maxY, point.longitude)
})
const midX = (minX + maxX) / 2
const midY = (minY + maxY) / 2
const deltaX = (maxX - minX)
const deltaY = (maxY - minY)
return {
latitude: midX,
longitude: midY,
latitudeDelta: deltaX,
longitudeDelta: deltaY
}
}
class Map extends Component {
componentDidMount() {
const { store } = this.context
this.unsubscribe = store.subscribe(() => { })
const markers$ = Observable.from(this.props.markers)
markers$.subscribe(x => console.log('observable', x))
}
componentWillUnmount() {
this.unsubscribe()
}
render() {
return (
<Container>
<MapView
style={styles.map}
region={this.props.region}
onRegionChangeComplete={this.props.onRegionChange}
>
{
this.props.markers.map(marker => {
return (
<MapView.Marker
coordinate={{ latitude: marker.latitude, longitude: marker.longitude }}
title={marker.name}
/>
)
})}
</MapView>
<Button
small
icon
style={mapStyle.toggleMenuButton}
onPress={() => this.props.onToggleMenuClick()}>
<Icon name="sliders" size={20} color="#FFFFFF" />
</Button>
</Container>
)
}
}
Map.contextTypes = {
store: React.PropTypes.object
}
Map.propTypes = {
region: React.PropTypes.shape({
latitude: React.PropTypes.number,
longitude: React.PropTypes.number,
latitudeDelta: React.PropTypes.number,
longitudeDelta: React.PropTypes.number
}).isRequired,
onRegionChange: React.PropTypes.func.isRequired,
onToggleMenuClick: React.PropTypes.func.isRequired,
markers: React.PropTypes.array
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Map)
const styles = StyleSheet.create({
map: {
...StyleSheet.absoluteFillObject,
zIndex: -1
}
})
markers.selector.js
import { createSelector } from 'reselect'
const searchResultsSelector = state => {
return state.get('searchResults')
}
const selectMarkers = createSelector(
searchResultsSelector,
(searchResults) => {
const shops = searchResults ? searchResults.map(result => {
return result.shops.map(shop => {
return {
id: shop.f1,
name: shop.f2,
latitude: shop.f4,
longitude: shop.f3
}
})
}) : searchResults
const shopIds = []
const flattenedShops = [].concat.apply([], shops)
const uniqueShops = flattenedShops.map(shop => {
if (!shopIds.includes(shop.id)) {
shopIds.push(shop.id)
return shop
}
})
const finalMarkers = uniqueShops.filter(n => n != undefined)
return finalMarkers
}
)
export default selectMarkers
答案 0 :(得分:1)
[编辑]
下面是使用rx observables的解决方案,但在发布之后很快,我在想:您确定需要Observables
的强大功能来实现您的目标吗?
我认为您应该考虑仅使用componentWillReceiveProps
这是React方式来观察变化。我认为它可能非常适合你的需求
您可以在此回调中完全触发getRegionForCoordinates
和this.props.updateRegion
,而无需任何可观察的内容。
[结束编辑]
我看到你想要实现的目标。首先,您必须了解Observable.from
只接受单个对象/值,然后忽略对初始对象所做的任何更改。
const value = [1]
const obs$ = Observable.from(arr)
obs$.subscribe(console.log.bind(console)) // < this will only print once
value.push(2); // < this will be ignored and wont fire anything
但是,希望对你而言,有一种方法可以告诉我React
&#34;当物业发生变化时警告我#34;这正是你想要的。您希望捕获对this.props.markers
所做的任何更改,并将其提供给您的可观察对象。
我们将使用Rect componentWillReceiveProps
https://facebook.github.io/react/docs/react-component.html#componentwillreceiveprops来做到这一点
我们需要做的第一件事就是保留对marker$
的引用(因此可以通过其他方法访问它:
componentDidMount() {
//...
this.markers$ = new Observable.Subject()
//you can subscribe here to this observable
this.markers$.next(this.props.markers)
}
我们还需要实施将componentWillReceiveProps
markers$
componentWillReceiveProps(nextProps) {
this.markers$.next(nextProps.markers)
}
现在,这会触发subscribe
上的markers$
来电。