关闭 React-Native 中的 useEffect 内存泄漏
Closing a useEffect Memory Leak in React-Native
在我的 expo 应用程序中从一组地图导航到另一组地图时,如果我在地图加载完成之前导航,我经常会遇到此错误:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in %s.%s, a useEffect cleanup function
如何堵住这个内存泄漏?
下面是我的代码:
function MapsScreen({navigation}) {
const [user_latitude, setUserLatitude] = useState(0)
const [user_longitude, setUserLongitude] = useState(0)
const [position_error, setPositionError] = useState(null)
useEffect(() => {
navigator.geolocation.getCurrentPosition(position => {
setUserLatitude(position.coords.latitude);
setUserLongitude(position.coords.longitude);
setPositionError(null);
},
error => setPositionError(error.message),
{enableHighAccuracy: true, timeout: 20000, maximumAge: 2000}
);
});
原因:
You will get this warning when your component is unmounted from the memory and some async task is in the process like you make a network call and tries to leave the screen before resolving the promise.
解决方案:To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
您的问题的解决方案:查看您的代码,当组件尝试卸载时您正在更改状态,您必须使用 useEffect
hook,在setUserLatitude
、setUserLongitude
、setPositionError
前加一个flag,确保组件没有从内存中卸载
function MapsScreen({navigation}) {
const [user_latitude, setUserLatitude] = useState(0)
const [user_longitude, setUserLongitude] = useState(0)
const [position_error, setPositionError] = useState(null)
useEffect(() => {
let mounted = true // Add this
navigator.geolocation.getCurrentPosition(position => {
if(mounted){ // Add this
setUserLatitude(position.coords.latitude);
setUserLongitude(position.coords.longitude);
setPositionError(null);
}
},
error => setPositionError(error.message),
{enableHighAccuracy: true, timeout: 20000, maximumAge: 2000}
);
return () => {
mounted = false // add this
}
}, []);
了解更多信息 Clean up function
我同意瓦希德的回答,
顺便说一句,如果你的代码中已经有 react-navigation v5.x 会更容易,
很简单只用useFocusEffect
方法,只在屏幕聚焦时执行的函数。我给出了使用 isActive
标志检查器添加第二次检查的示例。
import React, { useEffect, useState } from 'react'
import { useFocusEffect } from '@react-navigation/native'
function MapsScreen({ navigation }) {
const [user_latitude, setUserLatitude] = useState(0)
const [user_longitude, setUserLongitude] = useState(0)
const [position_error, setPositionError] = useState(null)
useFocusEffect(
React.useCallback(() => {
let isActive = true
const fetchGeoPositon = () => {
navigator.geolocation.getCurrentPosition(
position => {
if (isActive) {
setUserLatitude(position.coords.latitude)
setUserLongitude(position.coords.longitude)
setPositionError(null)
}
},
error => isActive && setPositionError(error.message),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 2000 }
)
}
fetchGeoPositon()
return () => {
isActive = false
}
}, [])
)
}
在我的 expo 应用程序中从一组地图导航到另一组地图时,如果我在地图加载完成之前导航,我经常会遇到此错误:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in %s.%s, a useEffect cleanup function
如何堵住这个内存泄漏?
下面是我的代码:
function MapsScreen({navigation}) {
const [user_latitude, setUserLatitude] = useState(0)
const [user_longitude, setUserLongitude] = useState(0)
const [position_error, setPositionError] = useState(null)
useEffect(() => {
navigator.geolocation.getCurrentPosition(position => {
setUserLatitude(position.coords.latitude);
setUserLongitude(position.coords.longitude);
setPositionError(null);
},
error => setPositionError(error.message),
{enableHighAccuracy: true, timeout: 20000, maximumAge: 2000}
);
});
原因:
You will get this warning when your component is unmounted from the memory and some async task is in the process like you make a network call and tries to leave the screen before resolving the promise.
解决方案:To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
您的问题的解决方案:查看您的代码,当组件尝试卸载时您正在更改状态,您必须使用 useEffect
hook,在setUserLatitude
、setUserLongitude
、setPositionError
前加一个flag,确保组件没有从内存中卸载
function MapsScreen({navigation}) {
const [user_latitude, setUserLatitude] = useState(0)
const [user_longitude, setUserLongitude] = useState(0)
const [position_error, setPositionError] = useState(null)
useEffect(() => {
let mounted = true // Add this
navigator.geolocation.getCurrentPosition(position => {
if(mounted){ // Add this
setUserLatitude(position.coords.latitude);
setUserLongitude(position.coords.longitude);
setPositionError(null);
}
},
error => setPositionError(error.message),
{enableHighAccuracy: true, timeout: 20000, maximumAge: 2000}
);
return () => {
mounted = false // add this
}
}, []);
了解更多信息 Clean up function
我同意瓦希德的回答,
顺便说一句,如果你的代码中已经有 react-navigation v5.x 会更容易,
很简单只用useFocusEffect
方法,只在屏幕聚焦时执行的函数。我给出了使用 isActive
标志检查器添加第二次检查的示例。
import React, { useEffect, useState } from 'react'
import { useFocusEffect } from '@react-navigation/native'
function MapsScreen({ navigation }) {
const [user_latitude, setUserLatitude] = useState(0)
const [user_longitude, setUserLongitude] = useState(0)
const [position_error, setPositionError] = useState(null)
useFocusEffect(
React.useCallback(() => {
let isActive = true
const fetchGeoPositon = () => {
navigator.geolocation.getCurrentPosition(
position => {
if (isActive) {
setUserLatitude(position.coords.latitude)
setUserLongitude(position.coords.longitude)
setPositionError(null)
}
},
error => isActive && setPositionError(error.message),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 2000 }
)
}
fetchGeoPositon()
return () => {
isActive = false
}
}, [])
)
}