我是React Native的新手,在浏览我的应用程序组件时,我随机地在不同的屏幕中遇到此警告
ExceptionsManager.js:82警告:无法执行React state update on an unmounted component。这是空操作,但它表明应用程序中发生内存泄漏。要解决此问题,请在componentWillUnmount方法中取消所有订阅和异步任务。 在LoginScreen中(由n创建) 我尝试使用stackoverflow中找到的其他解决方案,但是会发生这种情况,并且在警告此应用程序之后,如果对我的应用程序执行任何额外操作,我将对应用程序使用setState冻结。
我尝试: -将此this._isMounted在componentDidMount中设置为true,在componentWillMount中设置为false。 -使用fetch更改呼叫我的请求并使用axios。 -更改导航以将导航从一个屏幕推送或替换为另一个屏幕。
我没事。
这是我的登录屏幕代码:
import React, { Component } from "react";
import {
StyleSheet,
View,
Image,
ImageBackground,
TextInput,
Text,
Alert,
TouchableOpacity
} from "react-native";
import IMAGELOGINBG from "../../Images/login_bg.png"; //'../../index.js';
import { Button } from "react-native-elements";
import { LinearGradient } from "expo-linear-gradient";
import USERICON from "../../Images/user-icon.png";
import PASSWORDICON from "../../Images/pass-icon.png";
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
// import {login} from './service.js';
import { BackHandler } from "react-native";
import ProgressLoader from "rn-progress-loader";
import withUnmounted from "@ishawnwang/withunmounted";
import yelp from "../api/yelp.js";
export function updateState(msg) {
if (isMounted == true) {
this.props.navigation.setParams({
notificationCount: global.NotificationCount
});
this.setState(
{
visible: false,
errorMsg: msg
},
() => {
this.timer = setTimeout(() => {
Alert.alert(msg);
if (global.loggedInControllers) {
this.props.navigation.navigate("ControllersScreen");
}
});
}
);
}
}
const login = async (userName, password) => {
var url =
"Login" +
"/" +
global.DeviceId +
"/" +
userName +
"/" +
password +
"/" +
global.OS;
try {
const response = await yelp.post(`/${url}`);
console.log(response.data);
var data = response.data;
global.loggedInControllers = data.Data;
if (data.NotificationsCount) {
global.NotificationCount = data.NotificationsCount;
}
_storeLoggedInUser(userName);
_getLoggedInUser();
updateState(data.ResponseMessage);
} catch (e) {
console.log(e);
updateState(e);
}
};
_storeLoggedInUser = async user => {
try {
await AsyncStorage.setItem("UserName", user);
} catch (error) {
console.log("Something went wrong", error);
}
};
_getLoggedInUser = async () => {
try {
let name = await AsyncStorage.getItem("UserName");
console.log("AFTER LOGIN " + name);
} catch (error) {
console.log("Something went wrong", error);
}
};
class LoginScreen extends Component {
constructor(props) {
super(props);
this.handleBackButtonClick = this.handleBackButtonClick.bind(this);
this.state = {
visible: false,
userName: "",
password: "",
errorMsg: ""
};
isMounted = false;
updateState = updateState.bind(this);
}
componentDidMount() {
const { navigation } = this.props;
//Adding an event listner om focus
//So whenever the screen will have focus it will set the state to zero
this.focusListener = navigation.addListener("didFocus", () => {
isMounted = true;
});
}
componentWillMount() {
BackHandler.addEventListener(
"hardwareBackPress",
this.handleBackButtonClick
);
}
componentWillUnmount() {
clearInterval(this.timer);
this.focusListener.remove();
BackHandler.removeEventListener(
"hardwareBackPress",
this.handleBackButtonClick
);
isMounted = false;
}
handleBackButtonClick() {
this.props.navigation.goBack(null);
return true;
}
state = {};
validate(text) {
var regx = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
if (!regx.test(text)) {
return false;
} else {
return true;
}
}
onClickBackToMainScreen() {
this.props.navigation.navigate("MainScreen");
}
onClickLogin() {
const { userName, password } = this.state;
if (userName.trim() === "") {
this.state.errorMsg = "Please enter username";
alert(this.state.errorMsg);
}
// else if (!this.validate(userName)) {
// this.state.errorMsg = 'Please enter valid email';
// alert(this.state.errorMsg)
// }
else if (password.trim() === "") {
this.state.errorMsg = "Please enter password";
alert(this.state.errorMsg);
} else {
this.setState({
visible: !this.state.visible
});
login(this.state.userName, this.state.password);
}
}
render() {
return (
<ImageBackground source={IMAGELOGINBG} style={styles.bgContainer}>
<KeyboardAwareScrollView
style={styles.scrollContainer}
contentContainerStyle={{ flexGrow: 1 }}
innerRef={ref => {
this.scroll = ref;
}}
onKeyboardWillShow={frames => {
console.log("Keyboard event", frames);
}}
>
<View style={styles.bigContainer}>
<View style={styles.container}>
<View style={styles.inputContainer}>
<Image source={USERICON} style={styles.inputIconImage} />
<TextInput
onFocus={event => {}}
allowFontScaling={false}
style={styles.editText}
placeholder="Username"
placeholderTextColor="gray"
underlineColorAndroid="transparent"
value={this.state.userName}
keyboardType="email-address"
onChangeText={userName => this.setState({ userName })}
/>
</View>
<View style={styles.inputContainer}>
<Image source={PASSWORDICON} style={styles.inputIconImage} />
<TextInput
allowFontScaling={false}
style={styles.editText}
placeholder="Password"
placeholderTextColor="gray"
underlineColorAndroid="transparent"
value={this.state.password}
onChangeText={password => this.setState({ password })}
secureTextEntry={true}
/>
</View>
<LinearGradient
colors={["#870000", "#540000", "#2f0000"]}
style={styles.buttonContainer}
start={{ y: 0.0, x: 0.0 }}
end={{ y: 0.0, x: 1.0 }}
>
<TouchableOpacity
style={styles.button}
onPress={this.onClickLogin.bind(this)}
>
<Text allowFontScaling={false} style={styles.textButton}>
Login
</Text>
</TouchableOpacity>
</LinearGradient>
<Text
allowFontScaling={false}
style={styles.textUnderline}
onPress={this.onClickBackToMainScreen.bind(this)}
>
Back to scan controller
</Text>
</View>
</View>
{/* </ScrollView> */}
</KeyboardAwareScrollView>
<View style={{ height: 80, width: 80, justifyContent: "center" }}>
<ProgressLoader
visible={this.state.visible}
isModal={true}
isHUD={true}
hudColor={"#fff"}
color={"#000"}
/>
</View>
</ImageBackground>
);
}
}
var styles = StyleSheet.create({
bgContainer: {
width: "100%",
height: "100%",
justifyContent: "center",
alignItems: "center"
},
bigContainer: {
width: "100%",
height: "100%",
flex: 1,
justifyContent: "center",
alignItems: "center"
},
scrollContainer: {
width: "100%",
height: "100%",
flex: 1
},
container: {
height: 222,
width: "80%",
flexDirection: "column",
alignItems: "center",
position: "absolute", //Here is the trick
bottom: 50 //Here is the trick
},
button: {
height: "100%",
width: "100%",
// fontSize: 22,
backgroundColor: "transparent"
},
buttonContainer: {
height: 62,
width: "100%",
borderRadius: 30
},
inputContainer: {
height: 60,
width: "100%",
borderRadius: 50,
borderWidth: 1,
borderColor: "#fff",
marginBottom: 20,
flexDirection: "row",
alignItems: "center",
backgroundColor: "#000",
opacity: 0.7
},
editText: {
height: "100%",
color: "#fff",
textAlignVertical: "top",
fontSize: 20,
width: "70%",
backgroundColor: "#000",
opacity: 0.7
},
bgImage: {
flex: 1,
width: undefined,
height: undefined
},
inputIconImage: {
width: "8%",
height: 25,
marginRight: "5%",
resizeMode: "contain",
marginLeft: "7%"
},
textUnderline: {
textDecorationLine: "underline",
textDecorationStyle: "solid",
color: "#fff",
marginTop: 10,
paddingBottom: 3,
fontSize: 18
},
textButton: {
color: "#fff",
fontSize: 16,
textAlign: "center",
textAlignVertical: "center",
width: "100%",
height: "100%",
lineHeight: 62,
alignSelf: "center"
}
});
export default withUnmounted(LoginScreen);
答案 0 :(得分:0)
这可能与bar
和isMounted
有关。从组件内部以及在updateState函数本身内部引用这两者时,您需要使用updateState
和this.isMounted
。
但是,this.updateState
对于组件来说有点奇怪。如果未安装组件,则此属性将不再存在,也将不再使用该方法来检查它。如果在未安装组件时仍在调用isMounted
,那将是一个更深层次的问题。
无论如何,请告诉我,在对updateState
和this.
的每个引用前面都添加isMounted