Issue
I'm stuck with an error for a week now where I get an error Uncaught (in Promise) TypeError: Cannot read properties of null (reading 'props') at StackManager.tsx:313
. I first ran into the error on mobile devices so Android and iOS devices. The application would run without a problem in the browser on a desktop device. But I then soon discovered that when I opened the developer tools in the Browser (Brave) and the screen size became smaller the error would suddenly appear as well on desktop devices. As soon as I close the developer tool or make the screen size big enough to be considered a desktop device the code would work after a refresh. Weirdly enough on Safari (MacBook Pro) it works even if you simulate an iPhone. On the iPhone if you open the website in Safari it doesn't work unless you simulate Safari (still on the phone) to be a Mac (desktop) then it works again...? So maybe there is a different JS depending on screen size?
My first assumption was that it's related with this
having a different scope. However I don't use this and only use arrow functions (no classes). I also find it very confusing that the error occurs after using a useState()
function (see stacktrace). The closest similar issue I found: Ionic Cannot read properties of null (reading 'removeChild') at StackManager.transitionPage however I don't see how I would have too many rerenders from my code.
App.tsx (where the error originates from)
/* imports omitted */
Amplify.configure(awsconfig);
setupIonicReact();
let default_user = {
first_name: "Max",
last_name: "Muster",
email: "[email protected]"
}
export const UserContext = React.createContext(default_user)
const App = () => {
const [appUser, setUser] = useState(default_user);
const [isAuthenticated, setLoggedIn] = useState(false);
const rememberDevice = async () => {
try{
const result = await Auth.rememberDevice();
console.log("Remembering Device:")
console.log(result)
}catch (error) {
console.log('Error remembering device', error)
}
}
const refreshAuthentication = async (bypassCache: boolean = false) => {
let user = null;
Auth.currentAuthenticatedUser({bypassCache: bypassCache})
.then(user => {
let { attributes } = user;
setUser({
first_name: attributes.given_name,
last_name: attributes.family_name,
email: attributes.email
});
console.log(user);
setLoggedIn(true); /* ####### Error occurs on this line ####### */
})
.catch(rejected => {
// promise rejects if user is not authenticated.
// error is expected
console.log("Not authenticated");
setLoggedIn(false);
})
};
const listener = (data :any) => {
switch(data.payload.event){
case 'signIn':
console.log("User signed in");
//refreshAuthentication();
//rememberDevice();
break;
case 'signOut':
console.log("User signed out");
refreshAuthentication();
break;
}
}
useEffect(() => {
refreshAuthentication(true);
}, []);
Hub.listen('auth', listener);
return (
<IonApp>
<UserContext.Provider value={appUser}>
{ isAuthenticated ?
<IonReactRouter>
<IonSplitPane contentId="main">
<Menu/>
<IonRouterOutlet id="main">
<Route path="/register">
<Register/>
</Route>
<Route path="/">
<Home/>
</Route>
<Route path="/personen">
<Personen/>
</Route>
<Route path="/calendar">
<Calendar/>
</Route>
<Route path="/page/:name" exact={true}>
<Page/>
</Route>
{(isPlatform("desktop") || isPlatform("tablet") || isPlatform("ipad")) &&
<Route path="/admin" exact={true}>
<Home/>
</Route>
}
</IonRouterOutlet>
</IonSplitPane>
</IonReactRouter>
: // not authenticated
<Login refreshAuthentication={refreshAuthentication} setLoggedIn={setLoggedIn} rememberDevice={rememberDevice}/>
}
</UserContext.Provider>
</IonApp>
);
};
export default App;
Login.tsx
/* imports */
// @ts-ignore
const Login = ({refreshAuthentication, setLoggedIn, rememberDevice}) => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [confirmPassword2, setConfirmPassword2] = useState("");
const [present, dismiss] = useIonToast();
const [loading, doneLoading] = useIonLoading();
const [showModal, setShowModal] = useState(false);
const [alert] = useIonAlert();
const history = useHistory();
const successfulLogin = (user: any, message: string) => {
rememberDevice();
present(message, 3000);
refreshAuthentication();
}
/**
* Cognito requires the same session for password change
* so a login attempt has to be made again and the
* new password submitted in the callback
*/
const completePassword = async () => {
if (confirmPassword === confirmPassword2) {
Auth.signIn(email,password)
.then(user => {
Auth.completeNewPassword(user, confirmPassword)
.then(user => {
// at this time the user is logged in if no MFA required
successfulLogin(user, "Login & password change successful");
}).catch(e => {
console.log(e);
alert("Error setting the new password");
});
}).catch(e => {
console.log(e);
alert("Error fetching current user");
});
} else {
alert("Passwords do not match", [{text:"Ok"}]);
}
}
const handleSubmit = async () => {
await loading("Logging you in...");
Auth.signIn(email, password)
.then(user => {
doneLoading();
console.log("User signed in:");
console.log(user);
if (user.challengeName === 'NEW_PASSWORD_REQUIRED') {
setShowModal(true);
} else {
// other situations
successfulLogin(user, "Login Successful");
}
}).catch(e => {
doneLoading();
console.log(e);
alert("Error logging you in: " + e.message);
}).finally(() => {
doneLoading();
});
};
return (
<IonPage>
<IonContent className="ion-padding">
<IonGrid>
<IonRow>
<IonCol>
<IonItem>
<IonLabel>Email</IonLabel>
<IonInput placeholder="[email protected]" type="email" onIonChange={(e: any) => {setEmail(e.target.value)}} />
</IonItem>
<IonItem>
<IonLabel>Password</IonLabel>
<IonInput placeholder="" type="password" onIonChange={(e: any) => {setPassword(e.target.value)}} />
</IonItem>
<IonButton onClick={handleSubmit} color="primary" expand="block" size="large" type="submit">Login</IonButton>
</IonCol>
</IonRow>
</IonGrid>
<IonModal isOpen={showModal} className="ion-padding">
<IonToolbar>
<IonTitle>Configuration</IonTitle>
<IonButtons slot="end">
<IonButton onClick={() => setShowModal(false)}>Cancel</IonButton>
</IonButtons>
</IonToolbar>
<IonContent>
<h2 className="ion-padding">New password required</h2>
<p className="ion-padding">You have to provide a new password for your account</p>
<IonItem>
<IonLabel>Password</IonLabel>
<IonInput placeholder="" type="password" onIonChange={(e: any) => {setConfirmPassword(e.target.value)}} />
</IonItem>
<IonItem>
<IonLabel>Confirm Password</IonLabel>
<IonInput placeholder="" type="password" onIonChange={(e: any) => {setConfirmPassword2(e.target.value)}} />
</IonItem>
<IonButton onClick={() => completePassword()} color="primary" expand="block" size="large" type="submit">Save</IonButton>
</IonContent>
</IonModal>
</IonContent>
</IonPage>
);
}
export default Login;
Solution
turns out the code
{(isPlatform("desktop") || isPlatform("tablet") || isPlatform("ipad")) &&
<Route path="/admin" exact={true}>
<Home/>
</Route>
}
is responsible for the error.
Not sure why but removing this code resolves the issue.
Answered By - joeck
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.