我尝试过使用 React Context 在网站上进行授权。我似乎每当刷新页面或更改页面时,上下文都会重置为默认值。我对 React 和 Web 开发还很陌生,我一直在关注这个教程。 我在我的项目中使用 Typescrypt(而不是像教程中那样的 js)、React、axios 和 jwt。
我的后端运行良好,我可以注册和验证用户。
这是我使用的上下文:
//The value of the context (State and setState)
interface AuthContextValue{
auth : {user: string ,pwd:string,roles:string,accessToken:string} | null;
setAuth : React.Dispatch<React.SetStateAction<{user:string,pwd:string,roles:string,accessToken:string} | null>>;
}
const AuthContext = createContext<AuthContextValue| undefined>(undefined);
interface AuthProviderProps {
children : React.ReactNode;
}
//Provider to wrap around the parent components which children/distant children might need the user logged
export const AuthProvider: React.FC<AuthProviderProps> = ({children}) => {
const [auth, setAuth] = useState<{user:string,pwd:string,roles:string,accessToken:string} | null>(null);
return (
<AuthContext.Provider value={{ auth, setAuth }}>
{children}
</AuthContext.Provider>
)
}
export default AuthContext;
这是我将上下文提供程序包装在我的应用程序中的索引
const container = document.getElementById('root');
if (container) {
const root = createRoot(container);
root.render(
<AuthProvider>
<App/>
</AuthProvider>
);
} else {
console.error('Failed to find the root element');
}
在我的应用程序中,我声明了我的路线,其中一条是私有的:
<Route element={<RequireAuth />}>
<Route path="/private" element = {<PrivateTestPage/>}/>
</Route>
这是 RequireAuth :
function RequireAuth() {
const auth = useAuth()?.auth;
const location = useLocation();
return (
auth?.user
? <Outlet/>
: <Navigate to="/login" state = {{from : location}} replace/>
);
}
export default RequireAuth
最后是我的登录页面:
const Login = (props:any) => {
const setAuth = useAuth();
const navigate = useNavigate();
const location = useLocation();
const from = location.state?.from?.pathname || "/";
const userRef = useRef(null);
const errRef = useRef(null);
const [user, setUser] = useState('');
const [pwd, setPwd] = useState('');
const [errMsg, setErrMsg] = useState('');
useEffect(() => {
setErrMsg('');
}, [user, pwd])
const handleSubmit = async (e: { preventDefault: () => void; }) => {
e.preventDefault();
try {
const response = await axios.post(LOGIN_URL,
JSON.stringify({ loginId:user, password:pwd }),
{
headers: { 'Content-Type': 'application/json' },
withCredentials: true
}
);
console.log(JSON.stringify(response?.data));
console.log(JSON.stringify(response));
const accessToken = response?.data?.accessToken;
const roles = 'to implement' //response?.data?.roles;
setAuth?.setAuth({ user, pwd, roles, accessToken });
setUser('');
setPwd('');
navigate(from, {replace:true})
} catch (err) {
setErrMsg('Login Failed');
}
}
return (
<>
<section>
<p ref={errRef} className={errMsg ? "errmsg" : "offscreen"} aria-live="assertive">{errMsg}</p>
<h1>Sign In</h1>
<form onSubmit={handleSubmit}>
<label htmlFor="username">Username:</label>
<input
type="text"
id="username"
ref={userRef}
autoComplete="off"
onChange={(e) => setUser(e.target.value)}
value={user}
required
/>
<label htmlFor="password">Password:</label>
<input
type="password"
id="password"
onChange={(e) => setPwd(e.target.value)}
value={pwd}
required
/>
<button>Sign In</button>
</form>
<p>
Need an Account?<br />
<span className="line">
<a href={REGISTERPAGE_URL}>Sign Up</a>
</span>
</p>
</section>
</>
)
}
export default Login
在显示所有页面的主页中,我添加了一个段落,让我看看上下文中是否有内容
<p>{setAuth?.auth?.user}</p>
。当用户在登录页面进行身份验证时,它会返回到之前浏览的页面。
当我浏览主页后登录时,我可以看到上下文检索了用户,但是一旦刷新页面,或更改页面并返回主页,上下文就会重置。
看来上下文值应该在刷新后重置。数据只是在会话之间不保存。
在这种情况下,最好使用 Redux 并将数据存储在本地实例或 cookie 中。它与该项目相得益彰。
再次强调,我不是专业人士,但如果您遇到类似问题,请查看 Redux 教程。