无法对卸载的组件执行 React 状态更新。使用效果挂钩

时间:2021-02-11 23:44:30

标签: react-native asynchronous use-effect

我似乎遗漏了一些关于避免内存泄漏的微妙之处。我已经阅读了一些关于如何使用异步函数避免这种情况的帖子,并尝试了一些方法。一切似乎都失败了。有人可以指出我做错了什么。

    useEffect(() => {
let ignore = false;
if (Platform.OS === "android" && !Constants.isDevice) {
  errorMessage("Oops, this will not work on Sketch in an Android emulator. Try it on your device!");
} else {

  // function to get location, weather and aurora info
  const getDataAsync = async () => {
    let { status } = await Permissions.askAsync(Permissions.LOCATION);
    if (status !== "granted") {
      setErrorMessage("Permission to access location was denied");
    }
    if (!ignore) {
      let location = await Location.getCurrentPositionAsync({});
       // do stuff with the location data, putting it into states
      fetch(`http://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${long}&APPID=${API_KEY}&units=metric`)
        .then(res => res.json())
        .then(json => {
          // do all sorts of stuff with the weather json, putting it into states
        });
      // Fetch the aurora data
      const myUTC = new Date().getTimezoneOffset();
      fetch(`http://api.auroras.live/v1/?type=ace&data=bz&tz=${myUTC}&colour=hex`)
        .then(res => res.json())
        .then(json => {
          // do stuff with the aurora json, put it into states
        });
      setIsLoaded(true); // this is for the activity indicator
    }
  }
  getDataAsync();
  return () => { ignore = true; }
}
}, []);

我在活动指示器旋转时故意快速切换屏幕并再次切换时出现错误。

2 个答案:

答案 0 :(得分:0)

将清理归还给一切!让我知道它是否有效

useEffect(() => {
  let ignore = false;
  if (Platform.OS === 'android' && !Constants.isDevice) {
    errorMessage(
      'Oops, this will not work on Sketch in an Android emulator. Try it on your device!',
    );
  } else {
    // function to get location, weather and aurora info
    const getDataAsync = async () => {
      let {status} = await Permissions.askAsync(Permissions.LOCATION);
      if (status !== 'granted') {
        setErrorMessage('Permission to access location was denied');
      }
      if (!ignore) {
        let location = await Location.getCurrentPositionAsync({});
        // do stuff with the location data, putting it into states
        fetch(
          `http://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${long}&APPID=${API_KEY}&units=metric`,
        )
          .then((res) => res.json())
          .then((json) => {
            // do all sorts of stuff with the weather json, putting it into states
          });
        // Fetch the aurora data
        const myUTC = new Date().getTimezoneOffset();
        fetch(
          `http://api.auroras.live/v1/?type=ace&data=bz&tz=${myUTC}&colour=hex`,
        )
          .then((res) => res.json())
          .then((json) => {
            // do stuff with the aurora json, put it into states
          });
        setIsLoaded(true); // this is for the activity indicator
      }
    };
    getDataAsync();
  }
  return () => {
    ignore = true;
  };
}, []);

答案 1 :(得分:0)

那很有希望,但不,它没有奏效。这可能与以下事实有关:有 2 个异步获取请求和一个“等待”位置请求,每个请求花费的时间不同。

我正在尝试使用 abortController 但这也不起作用:

      useEffect(() => {
  const abortController = new AbortController();
  if (Platform.OS === 'android' && !Constants.isDevice) {
    errorMessage(
      'Oops, this will not work on Sketch in an Android emulator. Try it on your device!',
    );
  } else {
    // function to get location, weather and aurora info
    const getDataAsync = async () => {
      let {status} = await Permissions.askAsync(Permissions.LOCATION);
      if (status !== 'granted') {
        setErrorMessage('Permission to access location was denied');
      }
        let location = await Location.getCurrentPositionAsync({signal: abortController.signal});
        // do stuff with the location data, putting it into states
        fetch(
          `http://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${long}&APPID=${API_KEY}&units=metric`, { signal: abortController.signal })
          .then((res) => res.json())
          .then((json) => {
            // do all sorts of stuff with the weather json, putting it into states
          });
        // Fetch the aurora data
        const myUTC = new Date().getTimezoneOffset();
        fetch(
          `http://api.auroras.live/v1/?type=ace&data=bz&tz=${myUTC}&colour=hex`, { signal: abortController.signal })
          .then((res) => res.json())
          .then((json) => {
            // do stuff with the aurora json, put it into states
          });
        setIsLoaded(true); // this is for the activity indicator
    };
    getDataAsync();
  }
  return () => {
      abortController.abort();
    }
}, []);

除了控制台内存泄漏错误,我还得到:

Possible Unhandled Promise Rejection (id: 0):
[AbortError: Aborted]

Possible Unhandled Promise Rejection (id: 1):
[AbortError: Aborted]