【问题标题】:"Error: you attempted to set the key `latitude` with the value `37.785834` on an object that is meant to be immutable and has been frozen."“错误:您试图在一个本应不可变且已被冻结的对象上设置键 `latitude` 的值为 `37.785834`。”
【发布时间】:2019-12-28 18:16:33
【问题描述】:

我在 React Native 中使用 navigator.geolocation API 将用户坐标设置为组件状态的一部分,MapView 应该用作 region 属性,并且运行 getCurrentPosition() 会抛出一个错误。

我不确定如何解决这个问题。错误表明这是一个不变性问题,尽管我确定我在应该使用的位置使用了 letconst

这是我的初始状态:

this.state = {
      data: {
        name: "Nie powinieneś tego widzieć.",
        address: "Wyślij zrzut ekranu tego widoku do nas na stronie dokosciola.pl w zakładce Kontakt.",
        url: "https://dokosciola.pl",
        coords: {
          latitude: undefined,
          longitude: undefined,
          latitudeDelta: 0.00922 * 1.5,
          longitudeDelta: 0.00421 * 1.5
        },
        hours: ["8:00", "10:00", "12:00"]
      }
};

这就是我使用地理定位 API 的方式:

locateUser = () => {
    navigator.geolocation.getCurrentPosition(
      position => {
        let state = this.state;
        state.data.coords.latitude = position.coords.latitude;
        state.data.coords.longitude = position.coords.longitude;
        this.setState(state);
        console.log(this.state);
      },
      error => Alert.alert("Ups!", `Wystąpił wewnętrzny błąd:\n${error}`),
      { enableHighAccuracy: true, timeout: 30000, maximumAge: 5000 }
    );
};

我在安装应用程序之前运行locateUser() 函数,所以:

componentWillMount() {
    this.locateUser();
}

这就是我使用react-native-maps 中的MapView 组件的方式:

<View style={{ flex: 1 }}>
        <MapView
          style={{ flex: 1 }}
          initialRegion={this.state.data.coords}
          region={this.state.data.coords}
          mapType={"mutedStandard"}
        >
          {data.map(element => {
            return (
              <ChurchMarker
                coords={element.coords}
                key={element.id}
                onPress={() => this.update(element)}
              />
            );
          })}
        </MapView>
</View>

ChurchMarker 是预煮的Marker,也来自react-native-mapsdata - 一个简单的对象数组,模拟潜在的 API 响应:

[
    {
        id: string,
        name: string,
        address: string,
        url: string,
        coords: {
            latitude: number,
            longitude: number
        },
        hours: string[]
    },
    ...
]

我希望MapView 在安装应用程序时关注用户坐标,但我在locateUser() 中指定的错误会执行,并显示以下消息:

Error: you attempted to set the key `latitude` with the value `37.375834` on an object that is meant to be immutable and has been frozen.

之后还有一个警告:

Warning: Failed prop type: The prop `region.latitude` is marked as required in `MapView`, but its value is `undefined`.

经度也一样。这意味着状态没有更新。 对此有任何修复吗?我在执行什么错误?

【问题讨论】:

  • 提醒:有不可变的对象吗?
  • @zixuan 没有,我没有在任何地方使用任何consts。我用了setState(),没有直接修改状态。一切似乎都很好。
  • 好的,API 呢?您将state定义为this.state,其中必须使用setState(),然后您直接将state的经纬度更改为经纬度。
  • @zixuan 你的意思是我应该直接用position坐标做setState,而不用let state = this.state?这不是您通常更新状态的方式吗?通过挑选我要修改的字段?
  • 我建议你尝试用对象的方式更新this.state

标签: reactjs react-native geolocation state immutability


【解决方案1】:

您必须始终使用对象方式更新您的state。在你的情况下你可以试试这个:

locateUser = () => {
    navigator.geolocation.getCurrentPosition(
      position => {
        this.setState({
         data.coords.latitude: position.coords.latitude,
         data.coords.longitude: position.coords.longitude 
       });
       console.log(this.state)
      },
      error => Alert.alert("Ups!", `Wystąpił wewnętrzny błąd:\n${error}`),
      { enableHighAccuracy: true, timeout: 30000, maximumAge: 5000 }
    );
};

或者如果对于新的state你想操作当前的state你必须使用this.setState的函数方式

更多信息请阅读docs的这一部分。

祝你好运:)

【讨论】:

    【解决方案2】:

    错误消息中清楚地描述了您的问题:您试图在本应不可变的对象上设置键

    当您编写let state = this.state 时,您正在创建一个对this.state 的引用,它是不可变的。

    因此,当您尝试为 state.data.coords.latitude 分配新值时,您正在改变状态对象,这是非法的。

    相反,您应该分两步重构代码:

    1. 简化状态对象以减少嵌套(去掉data层):
    this.state = {
        name: "Nie powinieneś tego widzieć.",
        address: "Wyślij zrzut ekranu tego widoku do nas na stronie dokosciola.pl w zakładce Kontakt.",
        url: "https://dokosciola.pl",
        coords: {
          latitude: undefined,
          longitude: undefined,
          latitudeDelta: 0.00922 * 1.5,
          longitudeDelta: 0.00421 * 1.5
        },
        hours: ["8:00", "10:00", "12:00"]
    }
    
    1. 创建一个newCoords 对象并将其设置为正确的值,然后使用setState 覆盖state.coords
    locateUser = () => {
        navigator.geolocation.getCurrentPosition(
          position => {
            const newCoords = {}
            newCoords.latitude = position.coords.latitude
            newCoords.longitude = position.coords.longitude
            this.setState({ coords: newCoords })
          },
          error => Alert.alert("Ups!", `Wystąpił wewnętrzny błąd:\n${error}`),
          { enableHighAccuracy: true, timeout: 30000, maximumAge: 5000 }
        );
    };
    

    【讨论】:

      猜你喜欢
      • 2019-01-20
      • 2021-05-29
      • 2016-11-11
      • 2018-02-13
      • 2017-02-26
      • 1970-01-01
      • 2021-06-04
      • 1970-01-01
      • 2020-05-23
      相关资源
      最近更新 更多