Location + mapview - ComponentWillMount 在渲染之前解析?反应本机 |世博会

Location + mapview - ComponentWillMount resolves before render does? React Native | Expo

我有时可以得到正确的位置,大部分时间在状态更新之前,render() 调用获取空状态。

我尝试添加异步 + 等待条件但无济于事。一旦将位置数据设置为状态,我如何确保渲染地图。

这是代码。

所以,也许我可以在某个地方放置 nexttick() 左右以确保使用更新的状态来渲染?

import React, { Component } from "react";
import {Platform,Text,Image,View,StyleSheet,Dimensions} from "react-native";
import { MapView, Constants, Location, Permissions } from "expo";

const { width, height } = Dimensions.get("window");

const SCREEN_HEIGHT = height;
const SCREEN_WIDTH = width;
const ASPECT_RATIO = width / height;
const LATITUDE_DELTA = 0.0922;
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;

export default class ComplaintScreen extends Component {
  state = {
    location: null,
    errorMessage: null,
    
    positionState: {
      latitude: 0,
      longitude: 0,
      latitudeDelta: 0,
      longitudeDelta: 0
    },

    markerPosition: {
      latitude: 0,
      longitude: 0
    }
  };

  async componentWillMount() {
    if (Platform.OS === "android" && !Constants.isDevice) {
      this.setState({
        errorMessage:
          "Oops, this will not work on Sketch in an Android emulator. Try it on your device!"
      });
    } else {
      await this._getLocationAsync();
    }
  }

  _getLocationAsync = async () => {
    let { status } = await Permissions.askAsync(Permissions.LOCATION);
    if (status !== "granted") {
      this.setState({
        errorMessage: "Permission to access location was denied"
      });
    }

    let location = await Location.getCurrentPositionAsync(
      {
        enableHighAccuracy: true, timeout:5000, maxiumumAge: 10000
      });
    this.setState({ location });
    var lat = parseFloat(location.coords.latitude);
    var long = parseFloat(location.coords.longitude);

   
    var region = {
      latitude: lat,
      longitude: long,
      latitudeDelta: LATITUDE_DELTA,
      longitudeDelta: LONGITUDE_DELTA
    };
     this.setState({ positionState: region });
     this.setState({ markerPosition: region });
  };


 render() {
    return (
      console.log(this.state.positionState),
      <View style={Styles.container}>
        <MapView style={Styles.map} initialRegion={this.state.positionState}>
          <MapView.Marker coordinate={this.state.markerPosition}>
            <View style={Styles.radius}>
              <View style={Styles.marker} />
            </View>
          </MapView.Marker>
        </MapView>
      </View>
    );
  }
}
const Styles = StyleSheet.create({
 {some styles were here removed to keep the post short}
});

我做了一些事情,比如添加一个 activity 加载器,然后检查坐标是否已更新,然后才显示地图。目前有效,如果有更好的方法,会喜欢的。

import React, { Component } from "react";
import {
  Platform,
  Text,
  Image,
  View,
  StyleSheet,
  Dimensions,
  ActivityIndicator,
} from "react-native";
import { MapView, Constants, Location, Permissions } from "expo";

const { width, height } = Dimensions.get("window");

const SCREEN_HEIGHT = height;
const SCREEN_WIDTH = width;
const ASPECT_RATIO = width / height;
const LATITUDE_DELTA = 0.0922;
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;

export default class ComplaintScreen extends Component {
  static navigationOptions = {
    title: "New Complaint",
    headerStyle: {
      backgroundColor: "#010245",
      paddingTop: Constants.statusBarHeight,
      height: 60 + Constants.statusBarHeight
    },
    headerTintColor: "#fff",
    headerRight: (
      <Image
        source={require("../assets/img/header/hr.png")}
        style={{ justifyContent: "center", padding: 3, margin: 3 }}
      />
    )
  };

  state = {
    location: null,
    errorMessage: null,
    loading: true, 
    loadingMap:false,
    positionState: {
      latitude: 0,
      longitude: 0,
      latitudeDelta: 0,
      longitudeDelta: 0
    },

    markerPosition: {
      latitude: 0,
      longitude: 0
    }
  };
  
  async componentWillMount() {
    Location.setApiKey('AIzaSyAHSZHScQK-AslKB8QSIyDfqwGc2adFaUM');
    if (Platform.OS === "android" && !Constants.isDevice) {
      this.setState({
        errorMessage:
          "Oops, this will not work on Sketch in an Android emulator. Try it on your device!"
      });
    } else {
      await this._getLocationAsync();
    }
  }

  _getLocationAsync = async () => {
    let { status } = await Permissions.askAsync(Permissions.LOCATION);
    if (status !== "granted") {
      this.setState({
        errorMessage: "Permission to access location was denied"
      });
    }

    let location = await Location.getCurrentPositionAsync(
      {
        enableHighAccuracy: true, timeout:5000, maxiumumAge: 10000
      });
    this.setState({ location });
    var lat = parseFloat(location.coords.latitude);
    var long = parseFloat(location.coords.longitude);

   
    var region = {
      latitude: lat,
      longitude: long,
      latitudeDelta: LATITUDE_DELTA,
      longitudeDelta: LONGITUDE_DELTA
    };
      this.setState({ positionState: region });
      this.setState({ markerPosition: region });
  };

componentDidUpdate(){
  if (this.state.positionState.latitude!=='0'){
  this.state.loadingMap = true; 
  this.state.loading = false;
  }  
}
 render() {
    return (
      console.log(this.state.positionState),
      
      <View style={Styles.container}>
      {this.state.loadingMap &&
        <MapView style={Styles.map} initialRegion={this.state.positionState}>
          <MapView.Marker coordinate={this.state.markerPosition}>
            <View style={Styles.radius}>
              <View style={Styles.marker} />
            </View>
          </MapView.Marker>
        </MapView>
      }
        {this.state.loading &&
          <View style={Styles.loading}>
            <ActivityIndicator size='large' />
          </View>
      } 
      </View>
    );
  }
}
const Styles = StyleSheet.create({
  radius: {
    height: 50,
    width: 50,
    borderRadius: 50 / 2,
    overflow: "hidden",
    backgroundColor: "rgba(0, 122, 255, 0.1)",
    borderWidth: 1,
    borderColor: "rgba(0, 112, 255, 0.3)",
    alignItems: "center",
    justifyContent: "center"
  },
  marker: {
    height: 20,
    width: 20,
    borderWidth: 3,
    borderColor: "white",
    borderRadius: 20 / 2,
    overflow: "hidden",
    backgroundColor: "#007AFF"
  },

  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#F5FCFF"
  },

  map: {
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    position: "absolute"
  },
  loading: {
    position: 'absolute',
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    alignItems: 'center',
    justifyContent: 'center'
  }
});

作为替代方案,您可能还想通过使用 MapView 的引用来调用 react-maps-native animateToRegion。

这是我建议的适用于我的项目的替代方案:

_getLocationAsync = async()=> {
let {status} = await Permissions.askAsync(Permissions.LOCATION);
if(status!=='granted'){
  this.setState({errorMessage:"Permissions not granted."})
}
let location = await Location.getCurrentPositionAsync({});
this.map.animateToRegion({
    latitude: location.coords.latitude,
    longitude: location.coords.longitude,
    latitudeDelta: 0.0922,
    longitudeDelta: 0.0421,
}, 200)}

在此处查看参考资料: MapView API