UPDATE: I've applied the instructor in this post, but even using the state isMounted
and the useEffect
cleanup function I still can't solve this problem. the code seems to work fine, but I always get this warning.
I have an app component that manages the navigation of two pages through conditional rendering, if I am logged in I enter one, if I am not I enter the other.
import {context} from "./components/context"
const Stack = createNativeStackNavigator();
export default function App() {
const [isLoggedIn, setLoggedIn] = useState(false);
useEffect(() => {
let isMounted = true;
let store = async () => {
await SecureStore.deleteItemAsync("accessToken")
let accessToken = await SecureStore.getItemAsync("accessToken");
if(accessToken && isMounted) {
setLoggedIn(true)
}
}
store().then()
return () => {
isMounted = false
}
}, [])
return (
<>
<NavigationContainer>
<context.Provider value={{isLoggedIn, setLoggedIn}}>
<Stack.Navigator >
<Stack.Screen name={isLoggedIn ? "HomePantry" : "Home"} component={isLoggedIn? HomePantry : Home} />
</Stack.Navigator>
</context.Provider>
</NavigationContainer>
</>
);
}
My file context.js
:
export const context = React.createContext({});
This is my simple home component (before user login).
export default function Home({navigation}) {
return (
<View>
<Text> My pantry </Text>
<UserLogin />
</View>
);
}
This is the UserLogin
child component. I am using the context to be able to update the isLoggedIn
state once the user has entered their correct credentials. The problem is that the state is updated when the app component is unmounted and this causes no-op.
I get this warning: "Can't perform a React state update on an unmounted component - memory leak?"
I haven't been able to resolve this situation yet if anyone has any ideas. thanks in advance.
import {context} from "./context";
export default function UserLogin() {
const contest = React.useContext(context)
return (
<View style={styles.inputsContainer}>
<Formik
initialValues={{ email: '', password: '' }}
onSubmit={
async (values, actions) => {
if(values.email.trim() !== "" && values.password.trim() !== ""){
const response = await fetch('https://lam21.iot-prism-lab.cs.unibo.it/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: values.email,
password: values.password
})
});
let json = await response.json()
if(json.accessToken){
contest.setLoggedIn(true)
await SecureStore.setItemAsync("accessToken", json.accessToken);
actions.resetForm({})
} else {
alert("Username o password sbagliati!")
}
}}}
>
{({ handleChange, handleBlur, handleSubmit, values }) => (
<View style={styles.inputsContainer}>
<Text style={styles.labelText}> Email </Text>
<TextInput
required
onChangeText={handleChange('email')}
onBlur={handleBlur('email')}
value={values.email}
placeholder={"Inserisci la tua mail.."}
style={styles.inputText}
/>
<Text style={styles.labelText}> Password </Text>
<TextInput
required
onChangeText={handleChange('password')}
onBlur={handleBlur('password')}
value={values.password}
placeholder={"Inserisci la tua password.."}
style={styles.inputText}
/>
<View style={styles.inputButton}>
<Button onPress={handleSubmit} title="Submit" color="purple" style={styles.inputButton} />
</View>
</View>
)}
</Formik>
</View>
);
}
The homepantry component after the login:
export default function HomePantry() {
return (
<View>
<Text> My pantry </Text>
</View>
);
}
The problem is when you set a state on a promise
. The component was mounted before the promise was resolved so you just need to check if it is still mounted;
useEffect(() => {
let isMounted = true;
let store = async () => {
let accessToken = await SecureStore.getItemAsync("accessToken");
if(accessToken && isMounted){
setLoggedIn(true)
}
}
store().then()
return () => {
isMounted = false;
};
},[]);