I have select options collection of cities. Default selected value is current location if i allow. But after i allowed location permission, can't select another value. So, i can select another city for one second and set state current city again.
navigation geolocation code:
const useCurrentLocation = () => {
// store location in state
const [location, setLocation] = useState();
// Success handler for geolocation's `getCurrentPosition` method
const handleSuccess = (position) => {
const { latitude, longitude } = position.coords;
setLocation({
latitude,
longitude
});
};
useEffect(() => {
if (!navigator.geolocation) {
return false;
}
// Call the Geolocation API
navigator.geolocation.getCurrentPosition(handleSuccess);
}, []);
// Expose location result
return { location };
};
export default useCurrentLocation;
find nearest city according to location coordinates and set loc code:
function Nearest({ loc, setLoc }) {
const { location } = useCurrentLocation();
const { city } = useCity();
location && NearestCity(location.latitude, location.longitude);
// Convert Degress to Radians
function Deg2Rad(deg) {
return (deg * Math.PI) / 180;
}
function PythagorasEquirectangular(lat1, lon1, lat2, lon2) {
lat1 = Deg2Rad(lat1);
lat2 = Deg2Rad(lat2);
lon1 = Deg2Rad(lon1);
lon2 = Deg2Rad(lon2);
var R = 6371; // km
var x = (lon2 - lon1) * Math.cos((lat1 + lat2) / 2);
var y = lat2 - lat1;
var d = Math.sqrt(x * x + y * y) * R;
return d;
}
function NearestCity(latitude, longitude) {
var minDif = 99999;
var closest;
var dif;
city.map((item, index) => {
dif = PythagorasEquirectangular(latitude, longitude, item.lat, item.lon);
if (dif < minDif) {
closest = index;
minDif = dif;
}
});
setLoc(city[closest]);
}
//select city
const handleChange = (e) => {
var index = e.target.selectedIndex;
setLoc(city[index]);
};
return select options:
<select value={loc.name} onChange={handleChange}>
{city.map((val, i) => (
<option id={i} key={i} value={val.name}>
{val.name} - {i}
</option>
))}
</select>
By setting the value to your react state, you've made it a controlled input.
One solution would be to export setLocation from your useCurrentLocation hook and use that instead of your setLoc (or call both if you need setLoc).
Another approach could be to use defaultvalue (uncontrolled input).
I resolved the problem!
the solution is putting NearestCity inside a useEffect that is triggered by location.
useEffect(() => {
location && NearestCity(location.latitude, location.longitude);
}, [location]);