You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase登录组件无法跳转至Dashboard组件问题求助

问题描述

我正在使用Firebase Authentication服务,期望用户输入账号密码登录成功后自动跳转至Dashboard组件,但当前Dashboard的路由无法正常生效。查阅Firebase官方文档未找到有效解决办法,恳请各位开发者帮忙解决。


相关代码

SignInForm.js

import React, { useState } from "react";
import { useNavigate } from "react-router-dom/dist";
import { signInWithEmailAndPassword, getAuth } from "firebase/auth";

const SignInForm = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const auth = getAuth();

  const signIn = (e) => {
    e.preventDefault();
    signInWithEmailAndPassword(auth, email, password)
      .then((userCredential) => {
        console.log(userCredential);
      })
      .catch((error) => {
        console.log(error);
      });
  };
  let navigate = useNavigate();
  const routeChange = () => {
    let path = `/resetpass`;
    navigate(path);
  };

  return (
    <div onClick={signIn}>
      <div className="sign min-h-screen bg-base-200">
        <div className="hero-content flex-col lg:flex-row-reverse">
          <div className="text-center lg:text-left">
            <h1 className="text-5xl font-bold">Sign In</h1>
          </div>
          <div className="card flex-shrink-0 w-full max-w-sm shadow-2xl bg-base-100">
            <div className="card-body">
              <div className="form-control">
                <label className="label">
                  <span className="label-text">Email</span>
                </label>
                <input
                  type="email"
                  placeholder="email"
                  value={email}
                  onChange={(e) => setEmail(e.target.value)}
                  className="input input-bordered"
                />
              </div>
              <div className="form-control">
                <label className="label">
                  <span className="label-text">Password</span>
                </label>
                <input
                  type="password"
                  placeholder="password"
                  value={password}
                  onChange={(e) => setPassword(e.target.value)}
                  className="input input-bordered"
                />
              </div>
              <label className="label">
                <a href="#" onClick={routeChange}>
                  Forgot Password?
                </a>
              </label>
              {/*<div>{active === true && <PasswordReset />}</div> */}
              <div className="form-control mt-6">
                <button type="submit" className="btn btn-primary">
                  Sign In
                </button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default SignInForm;

Dashboard.js

import { useEffect, useState } from "react";
import { Navigate } from "react-router-dom";

const Dashboard = () => {
  const [authenticated, setauthenticated] = useState(null);
  useEffect(() => {
    const loggedInUser = localStorage.getItem("authenticated");
    if (loggedInUser) {
      setauthenticated(loggedInUser);
    }
  }, []);

  if (!authenticated) {
    // Redirect
    return <Navigate replace to="/login" />;
  } else {
    return (
      <div>
        <p>Welcome to your Dashboard</p>
      </div>
    );
  }
};

export default Dashboard;

App.js

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import { Fragment } from "react";

import Home from "./Home/pages/Home";
import Navbar from "./shared/components/navigation/Navbar";
import "./App.css";
import React from "@heroicons/react";
import Contact from "./Contact/pages/Contact";
import Admin from "./Admin/pages/Admin";
import SignInForm from "./Contact/components/SignInForm";
import PasswordReset from "./Contact/components/PasswordReset";
import Dashboard from "./Contact/components/Dashboard";

function App() {
  return (
    <div className="root-div">
      <Router>
        <main>
          <Routes>
            <Route path="/signin" exact element={<SignInForm />} />
            <Route path="/dashboard" exact element={<Dashboard />} />
          </Routes>
        </main>
      </Router>
    </div>
  );
}

export default App;

解决方案

1. 修复登录成功后的跳转逻辑(SignInForm.js)

  • 移除外层div的onClick={signIn},改用form标签包裹表单元素,将signIn绑定到form的onSubmit事件,避免误触发登录
  • 在登录成功的then回调中添加跳转代码,并设置登录状态标记
  • 修正useNavigate的导入路径,去掉/dist

修改后的关键代码片段:

import { useNavigate } from "react-router-dom"; // 修正导入路径

const SignInForm = () => {
  // ...其他代码

  const signIn = (e) => {
    e.preventDefault();
    signInWithEmailAndPassword(auth, email, password)
      .then((userCredential) => {
        console.log(userCredential);
        // 登录成功后跳转至Dashboard并标记登录状态
        localStorage.setItem('authenticated', 'true');
        navigate('/dashboard');
      })
      .catch((error) => {
        console.log(error);
      });
  };

  // ...其他代码

  return (
    <div className="sign min-h-screen bg-base-200">
      <div className="hero-content flex-col lg:flex-row-reverse">
        {/* ...其他代码 */}
        <div className="card flex-shrink-0 w-full max-w-sm shadow-2xl bg-base-100">
          <div className="card-body">
            {/* 用form标签包裹表单元素 */}
            <form onSubmit={signIn}>
              {/* ...邮箱、密码输入框 */}
              <div className="form-control mt-6">
                <button type="submit" className="btn btn-primary">
                  Sign In
                </button>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
  );
};

2. 修复Dashboard的认证校验与路由跳转(Dashboard.js)

  • 修正跳转路径为/signin,与App.js中的登录路由匹配
  • 改用Firebase的onAuthStateChanged监听登录状态,比localStorage更可靠

修改后的完整代码:

import { useEffect, useState } from "react";
import { Navigate } from "react-router-dom";
import { getAuth, onAuthStateChanged } from "firebase/auth";

const Dashboard = () => {
  const [authenticated, setAuthenticated] = useState(null);
  const auth = getAuth();

  useEffect(() => {
    // 监听Firebase用户登录状态
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setAuthenticated(!!user); // 存在用户则标记为已认证
    });

    return () => unsubscribe(); // 组件卸载时取消监听
  }, [auth]);

  if (authenticated === null) {
    // 加载状态,可添加自定义loading组件
    return <div>Loading...</div>;
  }

  if (!authenticated) {
    return <Navigate replace to="/signin" />; // 修正跳转路径
  } else {
    return (
      <div>
        <p>Welcome to your Dashboard</p>
      </div>
    );
  }
};

export default Dashboard;

3. 确认路由配置(App.js)

当前路由已正确配置/signin和/dashboard,无需额外修改,若后续新增页面可按需添加路由规则。


内容的提问来源于stack exchange,提问作者Lajibolala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 05:29:57