-1

screen shot of warning

I am new in React native and randomly i faced this warning in different screen when navigate my application Components

ExceptionsManager.js:82 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 the componentWillUnmount method. in LoginScreen (created by n) i try with different solution found in stackoverflow but it will be happened and after this warning any extra action on my application i use setState on it my application freeze.

i try with: - set this._isMounted true in componentDidMount and false in componentWillMount. - change call my request with fetch and use axios. - change navigate to push or replace in navigation from one screen to another.

Nothing work with me.

this is my login screen code:

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);
NourhanAdel
  • 1
  • 1
  • 4
  • Does this answer your question? [Can't perform a React state update on an unmounted component](https://stackoverflow.com/questions/53949393/cant-perform-a-react-state-update-on-an-unmounted-component) – Alexander Santos Jan 02 '20 at 16:16
  • no , componentWillUnmount method not fire in some of screens. – NourhanAdel Jan 02 '20 at 16:53
  • 1
    Can you post the entire code for 'LoginScreen', please? It's hard to diagnose the problem without seeing what's going on. It looks like this component is listening for some kind of event that will change its state, and this isn't being removed when you leave the screen. – Flagship1442 Jan 02 '20 at 16:53
  • edited my question with loginscreen code – NourhanAdel Jan 02 '20 at 17:10

1 Answers1

0

This might be to do with isMounted and updateState. In referencing both of these from within the component, and inside the updateState function itself you need to use this.isMounted and this.updateState.

However, isMounted is a bit of a strange property for a component. If the component is not mounted then this property no longer exists, nor the method you are going to use to check it. If updateState is still being called when the component is not mounted that feels like a deeper problem.

Anyway, let me know if adding this. in front of every reference to isMounted and updateState works

Flagship1442
  • 1,688
  • 2
  • 6
  • 13
  • by adding this in front of updateState >> YellowBox.js:67 Possible Unhandled Promise Rejection (id: 0): TypeError: _this2.updateState is not a function .. – NourhanAdel Jan 04 '20 at 18:48
  • i need to ask how to cancel all subscriptions and asynchronous tasks in componentWillUnmount ? ,, memory leak problem happened when navigate more than one time in my screens not from first time , i use asyncStorage, setInterval , setTimout , and axios calls , could you please let me know how can i cancel all of them in componentWillUnmount ? – NourhanAdel Jan 04 '20 at 19:33