App.js

import React from "react";
import { createRoot } from "react-dom/client";
import { Provider } from "react-redux";
import configureStore from "./store/configureStore";
import { startSetExpenses } from "./actions/expenses";
import 'normalize.css/normalize.css';
import './styles/styles.scss';
import AppRouter from "./routers/AppRouter";
import 'react-dates/lib/css/_datepicker.css';
import { auth } from './firebase/firebase';
import { onAuthStateChanged } from "firebase/auth";
import { useNavigate } from "react-router-dom";

const root = createRoot(document.getElementById("app"));

const navigate = useNavigate();

const store = configureStore();

const jsx = (
    <Provider store={store}>
        <AppRouter />
    </Provider>
);

const loadingComponent = <div><p>Loading...</p></div>;

root.render(loadingComponent);

store.dispatch(startSetExpenses())
.then(() => {
    root.render(jsx);
})
.catch((error) => {
    console.error("Error fetching expenses:", error);
});

onAuthStateChanged(auth, (user) => {
    if(user){
        console.log("LoggedIN");
        navigate("/dashboard");
    }else{
        console.log("LoggedOUT");
        navigate("/");
    }
})

AppRouter.js:

import React from 'react';
import LoginPage from '../components/LoginPage';
import Header from '../components/Header';
import NotFound from '../components/NotFound';
import EditExpense from '../components/EditExpense';
import AddExpense from '../components/AddExpense';
import ExpenseDashboardPage from '../components/ExpenseDashboard';
import HelpPage from '../components/HelpPage';
import { Routes, Route, BrowserRouter } from 'react-router-dom';


const AppRouter = () => (
    <BrowserRouter >
            <Header/>
            <Routes >
                <Route path="/" element={<LoginPage />} />
                <Route path="/dashboard" element={<ExpenseDashboardPage />} />
                <Route path="/create" element={<AddExpense />} />
                <Route path="/edit/:id" element={<EditExpense />} />
                <Route path="/help" element={<HelpPage />} />
                <Route path="*" element={<NotFound />} /> 
            </Routes>
    </BrowserRouter>
);

export default AppRouter;

store.dispatch(startSetExpenses())用于从firebase获取初始数据.直到它得到解决,我在屏幕上呈现loadingComponent. 我期望使用react—router—dom中的useNavigate在用户未登录时导航到"/"路径,在onAuthStateChanged中,当用户登录时导航到"/dashboard". 但它不起作用.我该如何做到这一点?

推荐答案

您不能在React组件或自定义React钩子之外调用React钩子.我建议将useNavigate钩子调用和auth状态更改侦听器移动到AppRouter,并将BrowserRouter提升到索引文件中,以包装AppRouter,以提供路由上下文.

示例:

应用程序:

import React from "react";
import { createRoot } from "react-dom/client";
import { Provider } from "react-redux";
import { BrowserRouter } from "react-router-dom";
import 'react-dates/lib/css/_datepicker.css';
import configureStore from "./store/configureStore";
import 'normalize.css/normalize.css';
import { startSetExpenses } from "./actions/expenses";
import './styles/styles.scss';
import AppRouter from "./routers/AppRouter";
import { auth } from './firebase/firebase';

const root = createRoot(document.getElementById("app"));

const store = configureStore();

const jsx = (
  <Provider store={store}>
    <BrowserRouter>
      <AppRouter />
    </BrowserRouter>
  </Provider>
);

const loadingComponent = <div><p>Loading...</p></div>;

root.render(loadingComponent);

store.dispatch(startSetExpenses())
  .then(() => {
    root.render(jsx);
  })
  .catch((error) => {
    console.error("Error fetching expenses:", error);
  });

AppRouter:

import React from 'react';
import { Routes, Route, useNavigate } from 'react-router-dom';
import { onAuthStateChanged } from "firebase/auth";
import LoginPage from '../components/LoginPage';
import Header from '../components/Header';
import NotFound from '../components/NotFound';
import EditExpense from '../components/EditExpense';
import AddExpense from '../components/AddExpense';
import ExpenseDashboardPage from '../components/ExpenseDashboard';
import HelpPage from '../components/HelpPage';

const AppRouter = () => {
  const navigate = useNavigate();

  React.useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      if (user) {
        console.log("LoggedIN");
        navigate("/dashboard");
      } else {
        console.log("LoggedOUT");
        navigate("/");
      }
    });

    return unsubscribe;
  }, []);

  return (
    <>
      <Header />
      <Routes>
        <Route path="/" element={<LoginPage />} />
        <Route path="/dashboard" element={<ExpenseDashboardPage />} />
        <Route path="/create" element={<AddExpense />} />
        <Route path="/edit/:id" element={<EditExpense />} />
        <Route path="/help" element={<HelpPage />} />
        <Route path="*" element={<NotFound />} /> 
      </Routes>
    </>
  );
};

export default AppRouter;

Reactjs相关问答推荐

为什么VScode中的React应用程序无法识别文件夹 struct ?

在一个blog函数中调用setState钩子

如何使Reaction Select 选项菜单从选项数组的特定索引开始

Reaction Ploly:如何在多个子情节中共享zoom 状态

在动态React组件中删除事件侦听器

是否为Reaction中未使用的组件生成Tailwincss样式?

在reactjs中刷新页面时丢失状态值

标签文本删除了 MUI 概述的输入

React Context API 在 Next.js 中更改路由时获取默认数据

将 useRef 与 useImperativeHandle 一起使用时,React 不会重新渲染

如何在PrimeReact的表格中修改筛选图标功能

redux 工具包使用中间件构建器函数时,必须返回一个中间件数组

在 CrafterCMS Studio 中拖动字段

在 Nextjs13 应用程序目录中呈现从 supabase 获取的数据

在react 中从外部 api 渲染列表

使用dayjs时如何在输入类型日期时间本地字段中设置默认值?

Material UI:使用 mui 手风琴时出现props 类型失败:isValidElement 不是函数

导航到屏幕时,react 本机上下文状态变为未定义

如何在 Reactjs 中判断受保护路由上的用户角色?

网格项不缩小以适应包含的可滚动列表