【问题标题】:Can't perform a React state update on an unmounted component. useEffect Hook无法对未安装的组件执行 React 状态更新。使用效果挂钩
【发布时间】:2021-05-15 18:40:26
【问题描述】:

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

    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; }
}
}, []);

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

【问题讨论】:

    标签: react-native asynchronous use-effect


    【解决方案1】:

    在一切之外返回清理!让我知道它是否有效

    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】:

      这很有希望,但不,它没有奏效。这可能与以下事实有关:有 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]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-02
        • 1970-01-01
        • 2020-12-20
        • 2020-07-19
        • 2019-10-19
        • 2021-07-01
        • 2020-11-21
        相关资源
        最近更新 更多