# #reactjs #firebase #react-native #expo #use-effect
Вопрос:
Я новичок в react native и следовал учебнику на носителе о том, как подключиться к firebase auth. Кажется, все работает нормально, но я продолжаю получать это предупреждение ниже:
Предупреждение: Не удается выполнить обновление состояния реакции для размонтированного компонента. Это не операция, но это указывает на утечку памяти в вашем приложении. Чтобы исправить это, отмените все подписки и асинхронные задачи в функции очистки useEffect.
Я в значительной степени сделал именно то, что было сказано в учебнике, и попробовал еще несколько вещей, чтобы исправить это, но, похоже, ничего не работает. Вот код, на который указывает ошибка:
let currentUserUID = firebase.auth().currentUser.uid;
const [firstName, setFirstName] = useState('');
useEffect(() => {
getUserInfo();
})
async function getUserInfo(){
try {
let doc = await firebase
.firestore()
.collection('users')
.doc(currentUserUID)
.get();
if (!doc.exists){
Alert.alert('No user data found!')
} else {
let dataObj = doc.data();
setFirstName(dataObj.firstName)
}
} catch (err){
Alert.alert('There is an error.', err.message)
}
}
Было бы здорово, если бы кто-нибудь мог помочь мне решить эту проблему и объяснить, что именно пошло не так.
Это ссылка на учебник, которому я следовал:
Ответ №1:
Проблема здесь в том, что вы потенциально ставите в очередь обновление состояния после отключения компонента. Поскольку вы обращаетесь к своему firestore напрямую, асинхронно, вы можете использовать ссылку React для отслеживания того, установлен ли компонент, прежде чем ставить обновление в очередь.
const isMountedRef = React.ref(null);
useEffect(() => {
isMountedRef.current = true; // set true when mounted
return () => isMountedRef.current = false; // clear when unmounted
}, []);
useEffect(() => {
async function getUserInfo(){
try {
let doc = await firebase
.firestore()
.collection('users')
.doc(currentUserUID)
.get();
if (!doc.exists){
Alert.alert('No user data found!')
} else {
let dataObj = doc.data();
if (isMountedRef.current) { // <-- check if still mounted
setFirstName(dataObj.firstName);
}
}
} catch (err){
Alert.alert('There is an error.', err.message)
}
}
getUserInfo();
}, []); // <-- include dependency array, empty to run once when mounting
Ответ №2:
Ваша getInfoUser()
функция такова async
. Вы должны сделать что-то подобное в useEffect
:
useEffect(async () => { await getUserInfo(); }, [])
В качестве второго аргумента useEffect
используется массив зависимостей. Использование массива зависимостей эквивалентно componentDidMount
.
Ваш эффект будет иметь место только один раз, когда компонент будет впервые отрисован. Кроме того, бывают случаи, когда вам нужно предоставить функцию очистки в useEffect
чем-то подобном:
return () => {
//do something or cancel a subscription
}
Комментарии:
1.
useEffect
ответные вызовы hook не могут бытьasync
, поэтомуgetUserInfo
объявляются отдельно и вызываются в ответном вызове hook. Это не очень хороший ответ, так как вы в основном сказали сделать то же самое, что уже указано в предупреждении React.