android – Ionic react error on small screen devices: Cannot read properties of null in StacakManager

[ad_1]

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: "max@muster.ch"
}
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="name@email.com" 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;

Stacktrace of the error:
Stacktrace

StackManager.tsx:313
StackManager.tsx:313

[ad_2]

Source link

Leave a Reply

Your email address will not be published.