Exception thrown while executing UI block: Invalid Region

Viewed 624

I am trying to get the user location in my React Native app and move my MapView to that location. When the app loads, it shows the location (by default, not because of my action), but when the action is executed I get this error:

Exception thrown while executing UI block: 
Invalid Region <center:+37.33233141, -122.03121860 span: +0.00044916, -0.05737702>

The region object being passed to my MapView (from my location actions) is

{
  latitude: 37.33233141,
  longitude: -122.0312186,
  accuracy: 0.05,
  latitudeDelta: 0.0004491555874955085,
  longitudeDelta: -0.05737702242408729
};

I actually copied the code from an old project that had had the same problem and then at some point stopped having the problem.

Anyway, here's my code:

MapScreen.js

import React, { Component } from "react";
import MapView, { Marker, Callout } from "react-native-maps";
import { connect } from "react-redux";

import { View, Button, Text, Platform, TextInput } from "react-native";

const CurrentRegionMarker = ({ currentRegion }) => {
  return currentRegion && currentRegion.showMarker ? (
    <Marker coordinate={currentRegion} pinColor={"green"} />
  ) : null;
};

class MapScreen extends Component {

  state = { region: null };

  render() {
    return (
      <View style={styles.container}>   
        <MapView
          style={{ flex: 1 }}
          showsUserLocation={true}
          region={this.props.currentRegion}
        >          
          <CurrentRegionMarker currentRegion={this.props.currentRegion} />
        </MapView>
      </View>
    );
  }
}

export default connect(({ location }) => ({
  currentRegion: location.currentRegion
}))(MapScreen);

locationActions.js

// @flow
import * as Location from "expo-location";
import * as Permissions from "expo-permissions";
import type {
  Location as LocationType,
  LocationAction
} from "../reducers/locationReducer";
import type { Saga } from "redux-saga";
import { call, put, select, takeEvery, all } from "redux-saga/effects";

export function getLocationAsync(): LocationAction {
  return { type: "USER_LOCATION_START" };
}

export function* getLocationSaga(): Saga<void> {
  try {
    const region = yield call(getUserLocation);
    yield put({ type: "USER_LOCATION_SUCCESS", region });
  } catch (error) {
    yield put({ type: "USER_LOCATION_FAILURE", error: error.message });
  }
}

async function getUserLocation(): LocationType {
  let { status } = await Permissions.askAsync(Permissions.LOCATION);
  if (status !== "granted") {
    return console.warn("Permission to access location was denied");
  }
  let location = await Location.getCurrentPositionAsync({});
  let { latitude, longitude } = location.coords;
  let accuracy = 0.05;
  let region = { latitude, longitude, accuracy };
  console.log("direct", calculateRegion(region));

  console.log("interpolated", { ...region, ...calculateRegion(region) });
  return { ...calculateRegion(region), accuracy };
}

function calculateRegion({
  latitude,
  longitude,
  accuracy = 0.05
}): LocationType {
  const oneDegreeOfLongitudeInMeters = 111.32;
  const circumference = 40075 / 360;
  const latitudeDelta = accuracy / oneDegreeOfLongitudeInMeters;
  const longitudeDelta = accuracy * (1 / Math.cos(latitude * circumference));
  const region = { latitude, longitude, latitudeDelta, longitudeDelta };
  return region;
}

export default function* locationSaga(): Saga<void> {
  yield all([yield takeEvery("USER_LOCATION_START", getLocationSaga)]);
}

locationReducer.js

// @flow

const initialState: LocationState = {
  currentRegion: {
    latitude: 0,
    longitude: 0,
    latitudeDelta: 0.00922,
    longitudeDelta: 0.00421,
    showMarker: false
  }
};

export default function dealsReducer(
  state: LocationState = initialState,
  action: LocationAction
): LocationState {
  switch (action.type) {
    case "USER_LOCATION_SUCCESS":
      return { ...state, currentRegion: action.region };
    case "USER_LOCATION_FAILURE":
      return { ...state, error: action.error };
    default:
      return state;
  }
}

export type Location = {
  latitude: number,
  longitude: number,
  latitudeDelta: number,
  longitudeDelta: number,
  showMarker?: boolean
};
type LocationState = {
  +currentRegion: Location,
  +error: ?string
};

export type LocationAction =
  | { type: "USER_LOCATION_START" }
  | {
      type: "USER_LOCATION_SUCCESS",
      region: Location
    }
  | {
      type: "USER_LOCATION_FAILURE",
      error: string
    };

Update: It appears that the longitudeDelta and latitudeDelta values were the problem. Right now I'm using hard-coded values for these, but I'm still not sure why this code is working as is in one app and not another.

0 Answers
Related