Я пытаюсь создать простое приложение аутентификации на нативном реагировании с использованием firebase. В файле App. js я использую ловушку useEffect для инициализации экземпляра firebase в моем приложении, а также объявляю функцию для обновления локального состояния (loggedIn) всякий раз, когда пользователь входит в систему или выходит из нее. Когда я пытаюсь войти в систему с помощью электронной почты и пароля, я могу показать кнопку «Выйти», но появляется это предупреждение:
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,
in LoginForm (at App.js:25)
- node_modules\react-native\Libraries\YellowBox\YellowBox.js:63:8 in console.error
- node_modules\expo\build\environment\muteWarnings.fx.js:27:24 in error
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:645:36 in warningWithoutStack
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:20432:6 in warnAboutUpdateOnUnmountedFiberInDEV
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:18518:41 in scheduleUpdateOnFiber
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:11484:17 in dispatchAction
* [native code]:null in dispatchAction
* src\components\LoginForm.js:13:8 in LoginForm
* src\components\LoginForm.js:25:24 in onButtonPress
- node_modules\regenerator-runtime\runtime.js:45:44 in tryCatch
- node_modules\regenerator-runtime\runtime.js:271:30 in invoke
- node_modules\regenerator-runtime\runtime.js:45:44 in tryCatch
- node_modules\regenerator-runtime\runtime.js:135:28 in invoke
- node_modules\regenerator-runtime\runtime.js:145:19 in Promise.resolve.then$argument_0
- node_modules\promise\setimmediate\core.js:37:14 in tryCallOne
- node_modules\promise\setimmediate\core.js:123:25 in setImmediate$argument_0
- node_modules\react-native\Libraries\Core\Timers\JSTimers.js:146:14 in _callTimer
- node_modules\react-native\Libraries\Core\Timers\JSTimers.js:194:17 in _callImmediatesPass
- node_modules\react-native\Libraries\Core\Timers\JSTimers.js:458:30 in callImmediates
* [native code]:null in callImmediates
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:407:6 in __callImmediates
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:143:6 in __guard$argument_0
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:384:10 in __guard
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:142:17 in __guard$argument_0
* [native code]:null in flushedQueue
* [native code]:null in invokeCallbackAndReturnFlushedQueue
Что я могу сделать, чтобы это исправить?
Приложение. js (Основной входной файл):
import { StyleSheet, View } from "react-native";
import { Button } from "react-native-elements";
import { Header, Spinner, CardSection } from "./src/components/common";
import LoginForm from "./src/components/LoginForm";
import firebase from "firebase";
export default function App() {
const [loggedIn, setLoggedIn] = useState(null);
const renderContent = () => {
switch (loggedIn) {
case true:
return (
<CardSection>
<View style={{ flex: 1 }}>
<Button
title="Log Out"
onPress={() => firebase.auth().signOut()}
/>
</View>
</CardSection>
);
case false:
return <LoginForm />;
default:
return (
<CardSection>
<Spinner size="large" />
</CardSection>
);
}
};
useEffect(() => {
if (!firebase.apps.length) {
try {
firebase.initializeApp({
apiKey: "AIzaSyC6zF09VjQS9kYOK6OsiBrXeVdMWQEt-5k",
authDomain: "auth-b4c8c.firebaseapp.com",
databaseURL: "https://auth-b4c8c.firebaseio.com",
projectId: "auth-b4c8c",
storageBucket: "auth-b4c8c.appspot.com",
messagingSenderId: "270113167666",
appId: "1:270113167666:web:3c74e7b22f7c6cf6c6df2b",
measurementId: "G-9EMRRJ6GKX"
});
firebase.auth().onAuthStateChanged(user => {
if (user) {
setLoggedIn(true);
} else {
setLoggedIn(false);
}
});
} catch (err) {
console.error("Firebase initialization error.", err.stack);
}
}
}, []);
return (
<View>
<Header headerText="Authentication" />
{renderContent()}
</View>
);
}
LoginForm. js файл:
import React, { useState } from "react";
import { View, Text, StyleSheet } from "react-native";
import { Card, CardSection, Input, Spinner } from "./common";
import { Button } from "react-native-elements";
import firebase from "firebase";
const LoginForm = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [errorMessage, setErrorMessage] = useState("");
const [loading, setLoading] = useState(false);
const onLoginSuccess = () => {
setEmail("");
setPassword("");
setLoading(false);
setErrorMessage("");
};
const onLoginFail = () => {
setErrorMessage("Authentication failed. Try again.");
setLoading(false);
};
const onButtonPress = async () => {
setErrorMessage("");
setLoading(true);
try {
await firebase.auth().signInWithEmailAndPassword(email, password);
onLoginSuccess();
} catch (e1) {
console.log(e1);
try {
await firebase.auth().createUserWithEmailAndPassword(email, password);
onLoginSuccess();
} catch (e2) {
console.log(e2);
onLoginFail();
}
}
};
return (
<Card>
<CardSection>
<Input
secureTextEntry={false}
placeholder="abc@example.com"
label="Email:"
value={email}
onChangeText={text => setEmail(text)}
/>
</CardSection>
<CardSection>
<Input
secureTextEntry={true}
placeholder="password"
value={password}
onChangeText={password => setPassword(password)}
label="Password:"
/>
</CardSection>
{errorMessage ? (
<Text style={styles.errorTextStyle}>{errorMessage}</Text>
) : null}
<CardSection>
{loading ? (
<Spinner size="small" />
) : (
<View style={{ flex: 1 }}>
<Button title="Log in" onPress={() => onButtonPress()} />
</View>
)}
</CardSection>
</Card>
);
};
const styles = StyleSheet.create({
errorTextStyle: {
fontSize: 20,
alignSelf: "center",
color: "red"
}
});
export default LoginForm;
Все остальные компоненты, такие как Header / Spinner et c. не имеют никакого отношения к состоянию напрямую и предназначены для презентаций / стилей, поэтому здесь я не включаю их код.