我使用了 react-router-dom v6 和 google firebase 身份驗證。在 react-router dom v5 中,我添加了它,它運行良好,在 v6 中,我從 v6 檔案中更改了一些內容。我找不到錯誤的。
使用Firebase.js:
import { useEffect, useState } from "react";
import initializeFirebase from "./../Pages/Authentication/firebase/firebase.init";
import {
getAuth,
createUserWithEmailAndPassword,
signInWithEmailAndPassword,
onAuthStateChanged,
updateProfile,
signOut,
} from "firebase/auth";
initializeFirebase();
const useFirebase = () => {
const [user, setUser] = useState({});
const [userData, setUserData] = useState({});
const [isLoading, setIsLoading] = useState(false);
const [optStatus, setOtpStatus] = useState("");
const [registrationStatus, setRegistrationStatus] = useState(false);
const [authError, setAuthError] = useState("");
const [admin, setAdmin] = useState(false);
const [assitantAdmin, setAssistantAdmin] = useState(false);
const [applicant, setApplicant] = useState(false);
const auth = getAuth();
const defaultOTP = "123456";
const registerUser = (
email,
password,
name,
phone,
dateOfBirth,
institutionId,
employeeId,
employeeType,
institution,
requestedRole,
role
) => {
setIsLoading(true);
createUserWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
setAuthError("");
const newUser = {
email,
displayName: name,
photoURL: "",
phoneNumber: phone,
dateOfBirth,
institutionId,
employeeId,
employeeType,
institution,
requestedRole,
role,
};
setUser(newUser);
//save user to the database
saveUser(
email,
name,
"",
phone,
dateOfBirth,
institutionId,
employeeId,
employeeType,
institution,
requestedRole,
role,
"POST"
);
// send name to firebase after register with email and password
updateProfile(auth.currentUser, {
displayName: name,
})
.then(() => {})
.catch((error) => {});
})
.catch((error) => {
setAuthError(error.message);
})
.finally(() => setIsLoading(false));
};
// sign is with email and password
const loginUserWithEmailPassword = (email, password, navigate) => {
setIsLoading(true);
signInWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
// const destination = location?.state?.from || "/";
navigate("/home");
setAuthError("");
})
.catch((error) => {
setAuthError(error.message);
})
.finally(() => setIsLoading(false));
};
//observe user state
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
setUser(user);
} else {
setUser({});
setUserData({});
}
});
setIsLoading(false);
return () => unsubscribe;
}, []);
//check and set admin
useEffect(() => {
fetch(`http://localhost:5000/users/${user.email}`)
.then((res) => res.json())
.then((data) => {
setUserData(data.userData);
setAdmin(data.admin);
setAssistantAdmin(data.assitantAdmin);
setApplicant(data.applicant);
});
}, [user.email]);
// save users into database
const saveUser = (
email,
displayName,
photoURL,
phoneNumber,
dateOfBirth,
institutionId,
employeeId,
employeeType,
institution,
requestedRole,
role,
method
) => {
const user = {
email,
displayName,
photoURL,
phoneNumber,
dateOfBirth,
institutionId,
employeeId,
employeeType,
institution,
requestedRole,
role,
};
if (method === "POST" || method === "PUT" || method === "DELETE") {
fetch("http://localhost:5000/users", {
method: method,
headers: {
"content-type": "application/json",
},
body: JSON.stringify(user),
}).then();
} else {
fetch("http://localhost:5000/users", {
method: method,
headers: {
"content-type": "application/json",
},
}).then();
}
};
// log out user
const logOut = () => {
signOut(auth)
.then(() => {
// Sign-out successful.
})
.catch((error) => {})
.finally(() => setIsLoading(false));
};
return {
user,
userData,
admin,
assitantAdmin,
applicant,
authError,
isLoading,
registrationStatus,
defaultOTP,
optStatus,
setIsLoading,
setOtpStatus,
setRegistrationStatus,
registerUser,
loginUserWithEmailPassword,
logOut,
};
};
export default useFirebase;
應用程式.js:
<AuthProvider>
<Router>
<Routes>
<Route
path='/dashboard/*'
element={
<PrivateRoute>
<Dashboard />
</PrivateRoute>
}
/>
<Route path='/login' element={<Login />} />
</Routes>
</Router>
</AuthProvider>
PrivateRoute.js:
// this is private route
const PrivateRoute = ({ children }) => {
let { user, isLoading } = useAuth();
let location = useLocation();
if (isLoading) {
return <Spinner className='my-5' animation='border' variant='success' />;
}
if (user?.email) {
return children;
}
return (
<Navigate
to={{
pathname: "/login",
state: { from: location },
}}
/>
);
};
export default PrivateRoute;
登錄.js:
const alertStyle = {
justifyContent: "center",
marginLeft: "auto",
marginRight: "auto",
};
用戶登錄頁面:
const Login = () => {
const [loginData, setLoginData] = useState({});
const { user, loginUserWithEmailPassword, isLoading, authError } = useAuth();
let location = useLocation();
const navigate = useNavigate();
const handleOnBlur = (e) => {
const field = e.target.name;
const value = e.target.value;
const newLoginData = { ...loginData };
newLoginData[field] = value;
setLoginData(newLoginData);
};
//handle log in using email password
const handleLogin = (e) => {
loginUserWithEmailPassword(
loginData.email,
loginData.password,
location,
navigate
);
e.preventDefault();
};
return (
<div>
<Navigation />
<div className='container'>
<p className='mt-5'>
<b>Log In for Admin</b>
</p>
<div className='mb-5'>
{/* register form */}
{!isLoading && (
<form onSubmit={handleLogin}>
<br />
<div className='mb-3'>
<input
type='email'
name='email'
onBlur={handleOnBlur}
style={{ width: "300px" }}
className='form-control mx-auto'
id='exampleFormControlInput1'
placeholder='Your Email'
/>
</div>
<div className='mb-3'>
<input
type='password'
name='password'
onBlur={handleOnBlur}
style={{ width: "300px" }}
className='form-control mx-auto'
id='exampleFormControlInput1'
placeholder='Your Password'
/>
</div>
<button
type='submit'
style={{ width: "300px" }}
className='btn btn-success mx-auto'
>
Login
</button>
</form>
)}
{/* Spinner */}
{isLoading && (
<Spinner className='my-5' animation='border' variant='success' />
)}
<p className='mt-3'>
<b>New User? </b>
<NavLink to='/signup' className='text-decoration-none'>
<b>Register & Submit Application</b>
</NavLink>
</p>
</div>
{/* success and error alert */}
{user?.email && (
<Alert severity='success' style={alertStyle}>
Account created successfully!
</Alert>
)}
{authError && (
<Alert severity='error' style={alertStyle}>
{authError}
</Alert>
)}
</div>
</div>
);
};
export default Login;
uj5u.com熱心網友回復:
問題
我認為問題在于初始isLoading狀態是錯誤的:
const [isLoading, setIsLoading] = useState(false);
并且初始user狀態是真實的:
const [user, setUser] = useState({});
在驗證加載狀態后重新加載頁面時永遠不會觸發:
//observe user state
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
setUser(user);
} else {
setUser({});
setUserData({});
}
});
setIsLoading(false);
return () => unsubscribe;
}, []);
在檢查失敗PrivateRoute,isLoading因為它是假的,所以user.email屬性被檢查。因為該user物件尚未填充,但重定向發生。
const PrivateRoute = ({ children }) => {
let { user, isLoading } = useAuth();
let location = useLocation();
if (isLoading) { // <-- (1) false, so no spinner
return <Spinner className='my-5' animation='border' variant='success' />;
}
if (user?.email) { // <-- (2) undefined, so no children
return children;
}
return (
<Navigate // <-- (3) navigate
to={{
pathname: "/login",
state: { from: location },
}}
/>
);
};
解決方案
我相信解決方案是微不足道的,從最初加載私有路由組件開始。
const [isLoading, setIsLoading] = useState(true);
這允許安裝身份驗證檢查適用于您的 UI 而不是針對它。
//observe user state
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
setUser(user);
} else {
setUser({});
setUserData({});
}
});
setIsLoading(false); // <-- (2) done initializing, isLoading false
return () => unsubscribe;
}, []); // <-- (1) mounting useEffect, start isLoading true
所以現在PrivateRoute組件將在初始渲染周期收到一個isLoadingtrue。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/429438.html
下一篇:為什么谷歌瀏覽器會自動將`http://app`重定向到`https://app`而不會重定向到`http://app2`或`http://napp`?
