我一直在做一个需要登录的项目。我一直在关注我在搜索信息时发现的this教程(这是本教程的第一种方式)。
但是,由于我想在单独的文件中创建项目,因此我无法直接按照教程进行操作。我有多个文件:
App.js
创建应用程序的位置。log-in.js
登录页面所在位置authoriser.js
处理用户的身份验证(按下按钮后)auth-server.js
创建一个所有用户所在的数据库我会展示每个文件的关键部分:
App.js
import React, { useEffect, useState } from 'react';
import { BrowserRouter as Router, Routes, Route, useNavigate } from 'react-router-dom';
import './App.css';
import Home from './pages/home';
import LogIn from './pages/log-in';
import Dashboard from './pages/dashboard';
import ProtectedRoute from './components/protected-route';
export default function App() {
const navigate = useNavigate();
const [username, setUsername] = useState('');
const [loggedIn, setLoggedIn] = useState(false);
useEffect(() => {
const user = JSON.parse(localStorage.getItem('user'));
if (!user || !user.token) {
setLoggedIn(false);
return;
}
fetch('http://localhost:3080/verify', {
method: 'POST',
headers: {
'jwt-token': user.token
},
})
.then((r) => r.json())
.then((r) => {
setLoggedIn('success' === r.message);
setUsername(user.username || '');
});
}, []);
return (
<Router>
<userContext.Provider value={username}>
<setUserContext.Provider value={username}>
<Routes>
<Route path='/' element={<Home />} />
<Route path='/login' element={<LogIn setLoggedIn={setLoggedIn} setUsername={setUsername} navigate={navigate} />} />
<Route element={<ProtectedRoute user={username} />}>
<Route path='/dashboard' element={<Dashboard loggedIn={loggedIn} setLoggedIn={setLoggedIn} />} />
</Route>
</Routes>
</setUserContext.Provider>
</userContext.Provider>
</Router>
);
}
log-in.js
import React, { useEffect, useState } from "react";
import LogInNavbar from "../components/navbar/login-navbar";
import Authoriser from "../components/authoriser";
import { useNavigate } from "react-router-dom";
export default function LogIn(props) {
const [formData, setFormData] = useState({ username: "", password: "" });
//const navigate = useNavigate();
const onChange = (event) => {
setFormData({...formData, [event.target.name]: event.target.value});
};
useEffect(()=>{
document.body.style.overflow = "hidden";
});
function authoriser(){
console.log("Authoriser");
Authoriser(formData, props);
if (props.loggedIn) {
localStorage.removeItem('user');
props.setLoggedIn(false);
} else {
props.navigate('/login');
}
}
return (
<>
<div className="Navbar">
<LogInNavbar />
</div>
<div className="LogIn">
<form className="LogInForm">
<h3>Iniciar Sesión</h3>
<label htmlFor="username">Nombre de Usuario</label>
<input type="text" placeholder="Nombre de Usuario" name="username" value={formData.username} onChange={onChange} />
<label htmlFor="password">Contraseña</label>
<input type="password" placeholder="Contraseña" name="password" value={formData.password} onChange={onChange} />
<button onClick={authoriser}>
Iniciar Sesión
</button>
</form>
</div>
</>
);
}
authoriser.js
export default function Authoriser( formData, props ) {
//const navigate = useNavigate();
const username = formData.username;
const password = formData.password;
const user = {username: username, password: password};
console.log(user);
if (username === ''){
window.alert("Introduzca su nombre de usuario");
return;
}
if (password === ''){
window.alert("Introduzca su contraseña");
return;
}
checkAccountExists((accountExists) => {
if (accountExists) proceedLoggingIn()
else if (
window.confirm(
'No existe ninguna cuenta con este nombre de usuario: ' + username + '. ¿Quieres crear una nueva cuenta?'
)
) {
proceedLoggingIn();
}
});
// Call the server API to check if the username ID already exists
const checkAccountExists = (callback) => {
fetch('http://localhost:3080/check-account', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username })
})
.then((r) => r.json())
.then((r) => {
callback(r?.userExists);
});
}
// Log in a user using username and password
const proceedLoggingIn = () => {
fetch('http://localhost:3080/check-account', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, password })
})
.then((r) => r.json())
.then((r) => {
if ('success' == r.message) {
localStorage.setItem('user', JSON.stringify({ username, token: r.token }));
props.setLoggedIn(true);
props.setUsername(username);
props.navigate('/dashboard');
} else {
window.alert('Wrong username or password');
}
})
}
}
当我执行该代码时,它返回多个错误,全部显示
useNavigate() may be used only in the context of a <Router> component.
如果有人能帮助我解决问题,我将不胜感激。
我尝试过传递
navigate
作为使用它们的道具(我认为它和我收到 Invalid hook call
错误之前一样有效)。
我不知道为什么我不能在
authoriser.js
文件中使用导航,因为它会删除该错误。我的理论是,这是因为它是一个事件处理程序(因为它处理登录单击按钮)。
我还看到该组件必须位于 Router 和 Routes 上,但它被包裹在其上。
我曾经在页面之间移动
<Link>
,但在这种情况下我不知道如何实现这种情况,因为它不返回页面元素。也许有一种方法可以调用其他网络路径,但我不知道它们以及如何在我的代码中实现它们。
App
渲染 Router
以及路由上下文。将 Router
移至 ReactTree 上方。
在组件渲染中
App
:
import { BrowserRouter as Router } from 'react-router-dom';
import App from './components/App';
...
<Router>
</App />
</Router>
应用程序
import React, { useEffect, useState } from 'react';
import { Routes, Route, useNavigate } from 'react-router-dom';
import './App.css';
import Home from './pages/home';
import LogIn from './pages/log-in';
import Dashboard from './pages/dashboard';
import ProtectedRoute from './components/protected-route';
export default function App() {
const navigate = useNavigate();
const [username, setUsername] = useState('');
const [loggedIn, setLoggedIn] = useState(false);
useEffect(() => {
const user = JSON.parse(localStorage.getItem('user'));
if (!user || !user.token) {
setLoggedIn(false);
return;
}
fetch('http://localhost:3080/verify', {
method: 'POST',
headers: {
'jwt-token': user.token
},
})
.then((r) => r.json())
.then((r) => {
setLoggedIn('success' === r.message);
setUsername(user.username || '');
});
}, []);
return (
<userContext.Provider value={username}>
<setUserContext.Provider value={setUsername}>
<Routes>
<Route path='/' element={<Home />} />
<Route
path='/login'
element={(
<LogIn
setLoggedIn={setLoggedIn}
setUsername={setUsername}
/>
)}
/>
<Route element={<ProtectedRoute user={username} />}>
<Route
path='/dashboard'
element={(
<Dashboard
loggedIn={loggedIn}
setLoggedIn={setLoggedIn}
/>
)}
/>
</Route>
</Routes>
</setUserContext.Provider>
</userContext.Provider>
);
}
有关上下文提供者和道具的附加说明。这些组件不应将
username
和 setUsername
作为 props 向下传递,而应使用提供的 React 上下文值,即使用 useContext
钩子。