I have a "dumb" component that displays the approx. distance between two locations.
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"
I want to enhance this component by updating the component whenever the browsers geo-location changes. So I created another component
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
My goal was to register the event listener for the geo-location updates only once in my app and not one listener for every component. I worry I create a circular reference when I save the component instances in a static array TrackingDistance.instances.
Also is it allowed to call the setState method of other components from outside the component itself (like I do in my location listener?)
Is there any other react pattern to solve such problem better? I can't use Mixins, cause I am using ES6 React component classes.
Aucun commentaire:
Enregistrer un commentaire