小屏幕设备上的离子反应错误:无法在 StacakManager 中读取 null 的属性

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

我被一个错误困扰了一个星期,现在我得到一个错误 Uncaught (in Promise) TypeError: Cannot read properties of null (reading 'props') at StackManager.tsx:313。我首先 运行 在移动设备上进入错误所以 Android 和 iOS 设备。该应用程序将 运行 在桌面设备上的浏览器中没有问题。但是我很快发现,当我在浏览器(Brave)中打开开发者工具并且屏幕尺寸变小时,桌面设备上也会突然出现错误。只要我关闭开发人员工具或使屏幕尺寸足够大以被视为桌面设备,代码就会在刷新后运行。奇怪的是,在 Safari (MacBook Pro) 上,即使您模拟 iPhone,它也能正常工作。在 iPhone 上,如果您在 Safari 中打开该网站,除非您将 Safari(仍在 phone 上)模拟为 Mac(桌面),否则它将再次运行。 .?所以也许有不同的 JS 取决于屏幕尺寸?

我的第一个假设是它与具有不同范围的 this 有关。但是我不使用它,只使用箭头函数(没有 类)。我还发现使用 useState() 函数后发生错误非常令人困惑(请参阅堆栈跟踪)。我发现的最接近的类似问题:Ionic Cannot read properties of null (reading 'removeChild') at StackManager.transitionPage 但是我不明白我的代码会如何重新呈现太多。

App.tsx(错误来源)

/* 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;

错误的堆栈跟踪:

StackManager.tsx:313

验证码

{(isPlatform("desktop") || isPlatform("tablet") || isPlatform("ipad")) &&
    <Route path="/admin" exact={true}>
        <Home/>
    </Route>
}

对错误负责。

不确定原因,但删除此代码可以解决问题。