小屏幕设备上的离子反应错误:无法在 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>
}
对错误负责。
不确定原因,但删除此代码可以解决问题。
我被一个错误困扰了一个星期,现在我得到一个错误 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>
}
对错误负责。
不确定原因,但删除此代码可以解决问题。