为什么这个反应登录页面不起作用?

问题描述 投票:0回答:1

我正在尝试制作一个反应应用程序,我想进行一些登录,然后可以访问主站点。问题是它根本没有真正发挥作用。使用正确的密码首次登录时,不会加载私人页面。但如果我然后返回并只需单击登录而不输入密码或登录,它就会加载正常。如果输入了错误的密码,它也不会重定向。

这个应用程序是在 next.js 中的 React 和 TypeScript 中构建的,但我无法使用任何服务器端渲染,因为这是在静态站点上进行的。

这是登录页面代码

'use client'
import React, {useState} from 'react';
import { AuthProvider, useAuth } from './AuthContext';
import { useNavigate } from 'react-router-dom';
import './index.css';

const LoginComp: React.FC = () => {
    const navigate = useNavigate();
    const { signin, isAuthenticated } = useAuth();
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');
  
    const handleLogin = () => {
      try{
        signin(username, password);
        navigate('/test');
      }
      catch{
        navigate('/');
      }
      
    };
  
    return (
      <div className="container">
          <div className="content">
              <form id='form'>
                  <img src='picture url' width='100%' alt='Logo' /><br />
                  <input id="uname" type="username" placeholder="Username" value={username} onChange={(e) => setUsername(e.target.value)} /><br />
                  <input id="pword" type="password" placeholder="Password" value={password} onChange={(e) => setPassword(e.target.value)} /><br />
                  <p id="error"></p>
                  <button id="submit" onClick={handleLogin}>Login</button>
              </form>
          </div>
      </div>
    );
  };
  const LoginPage: React.FC = () => {
    return(
        <AuthProvider>
            <LoginComp />
        </AuthProvider>
    );
  }
  export default LoginPage;

这是路由文件

'use client'
import React from 'react';
import { BrowserRouter, Route, Routes, HashRouter  } from 'react-router-dom';
import PrivateRoutes from './PrivateRoutes';
import LoginPage from './login';
import PrivatePage from './home';

const App: React.FC = () => {
    return (
        <BrowserRouter >
            <Routes>
                <Route  element={<LoginPage />} path="/"/>
                <Route element={<PrivateRoutes />}>
                    <Route element={<PrivatePage comp_name='/test'/>} path='/test'/>
                </Route>
            </Routes>
        </BrowserRouter>
    );
};
export default App;

这是私人页面文件

'use client'
import React from 'react';
import { Navigate, Outlet } from 'react-router-dom';

import { AuthProvider, useAuth } from './AuthContext';

function PrivateRouting() {
    const { isAuthenticated } = useAuth();
    return (
        isAuthenticated ? <Outlet /> : <Navigate to="/test" />
    );
}
function PrivateRoutes() {
    return(
        <AuthProvider>
            <PrivateRouting />
        </AuthProvider>
    );
};
export default PrivateRoutes;

这是我的身份验证文件

'use client'
import React, { createContext, useContext, useState } from 'react';
import Cookies from 'js-cookie';

interface AuthContextType {
    isAuthenticated: boolean;
    signin: (username: string, password: string) => Promise<void>; // Update signin function to return a promise
    signout: () => void;
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);

export const useAuth = () => {
    const context = useContext(AuthContext);
    if (!context) {
        throw new Error('useAuth must be used within an AuthProvider');
    }
    return context;
};

interface AuthProviderProps {
    children: React.ReactNode; // Define children prop
}

export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
    const [isAuthenticated, setIsAuthenticated] = useState<boolean>(() => {
        // Check cookies for authentication token
        return !!Cookies.get('token');
    });

    const signin = async (username: string, password: string) => {
        try {
            const formData = new FormData();
            formData.append('uname', username);
            formData.append('pword', password);

            const response = await fetch('https link to my public domain', {
                method: 'POST',
                body: formData,
            });

            if (!response.ok) {
                throw new Error('Authentication failed');
            }

            const data = await response.json();
            const token = data.token;
            const expiry = data.expiry;

            // Check if token and expiry exist
            if (!token || !expiry) {
                throw new Error('Token or expiry not received');
            }

            // Store the token in cookies with the provided expiry time
            const expirationTime = new Date();
            expirationTime.setMinutes(expirationTime.getMinutes() + 2);

            Cookies.set('token', token, { expires: expirationTime });
            setIsAuthenticated(true);
        } catch (error) {
            console.error('Signin failed:', error);
            throw error;
        }
    };


    const signout = () => {
        // Remove token from cookies
        Cookies.remove('token');
        setIsAuthenticated(false);
    };

    return (
        <AuthContext.Provider value={{ isAuthenticated, signin, signout }}>
            {children}
        </AuthContext.Provider>
    );
};

每次我做出一些改变,它都会破坏更多。

我对 React 很陌生,并且有一定的 Web 开发经验,因此任何有关 React 的一般提示也将不胜感激。

reactjs typescript next.js deployment react-router
1个回答
0
投票

登录组件中的

handleLogin
函数调用
signin
方法,但在导航之前不会等待
signin
完成。由于
signin
是一个异步函数,因此您应该在导航之前等待其完成。

const handleLogin = async (e) => {
  e.preventDefault(); // Prevent default form submission
  try {
    await signin(username, password);
    navigate('/test');
  } catch {
    navigate('/');
  }
};

您还使用

useNavigate
中的
react-router-dom
,它不是 Next.js 的一部分。在 Next.js 中,您应该使用
useRouter
中的
next/navigation
进行导航,

import { useRouter } from 'next/navigation';

// Inside your component
const router = useRouter();

// To navigate
router.push('/test');

在您的

PrivateRouting
组件中,您将未经身份验证的用户重定向到
/test
,这似乎是您的受保护路由。如果他们没有经过身份验证,您应该将他们重定向到登录页面 (
/
),

return (
    isAuthenticated ? <Outlet /> : <Navigate to="/" />
);
© www.soinside.com 2019 - 2024. All rights reserved.