我有一个"哑巴"显示大约的组件。两个地点之间的距离。
import React from "react"
const cos = Math.cos
const p = Math.PI / 180
function getDistance(lat1, lon1, lat2, lon2) {
var a = 0.5 - c((lat2 - lat1) * p)/2 +
c(lat1 * p) * c(lat2 * p) *
(1 - c((lon2 - lon1) * p))/2
return 12742 * Math.asin(Math.sqrt(a)) // 2 * R; R = 6371 km
}
let Distance = ({from,to}) => {
let distance = getDistance(
from.latitude,
from.longitude,
to.latitude,
to.longitude)
if (distance < 1.0) {
distance = (distance * 100) + "m"
} else {
distance = distance + "km"
}
return <span>{distance}</span>
}
}
Distance.displayName = "Distance"
我想通过在浏览器地理位置发生变化时更新组件来增强此组件。所以我创建了另一个组件
class TrackingDistance extends React.Component {
constructor(props) {
super(props)
this.updatePosition = this.updatePosition.bind(this)
if (TrackingDistance.lastPosition) {
this.updatePosition(TrackingDistance.lastPosition)
} else {
navigator.geolocation.getCurrentPosition(this.updatePosition)
}
}
updatePosition(position) {
this.setState({from: position.coords})
}
componentDidMount() {
if (TrackingDistance.instances.length === 0) {
TrackingDistance.watchId = navigator.geolocation.watchPosition(position => {
TrackingDistance.instances.map(instance => instance.updatePosition(position))
})
}
TrackingDistance.instances.push(this)
}
componentWillUnmount() {
TrackingDistance.instances.remove(this)
if (TrackingDistance.instances.length === 0) {
navigator.geolocation.clearWatch(TrackingDistance.watchId)
}
}
render() {
return this.state.from ? <Distance to={this.props.to} from={this.state.from}/> : null
}
}
TrackingDistance.instances = []
TrackingDistance.watchId = 0
TrackingDistance.lastPosition = null
我的目标是在我的应用中只为地理位置更新注册一次事件监听器,而不是每个组件都有一个监听器。我担心在将组件实例保存在静态数组TrackingDistance.instances
中时会创建循环引用。
也允许从组件本身外部调用其他组件的setState
方法(就像我在我的位置监听器中那样?)
还有其他反应模式可以更好地解决这个问题吗?我无法使用Mixins,因为我使用的是ES6 React组件类。