开发者问题收集

React Router 仅在刷新后渲染

2021-07-04
364

我正在尝试使用 react redux 和 router 创建一个 web 应用程序,但我遇到了一个奇怪的行为,Router 只在刷新时呈现。 那是我的 App.js

import React, { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Router, Switch, Route, Link } from "react-router-dom";
import { ModalProvider } from './modal/modalContext';
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import Login from "./components/Login";
import Register from "./components/Register";
import Home from "./components/Home";
import Profile from "./components/Profile";
import BoardUser from "./components/BoardUser";
import BoardModerator from "./components/BoardModerator";
import BoardAdmin from "./components/BoardAdmin";
import DataService from "./services/data.service";
import { logout } from "./actions/auth";
import { clearMessage } from "./actions/message";
import { setDc } from "./actions/dc";
import { history } from "./helpers/history";
import simplidc_logo from "./images/dns-24px.svg"
import DetailedRackCard from './components/detailed_rack_card'

const App = () => {
  const [showModeratorBoard, setShowModeratorBoard] = useState(false);
  const [showAdminBoard, setShowAdminBoard] = useState(false);

  const { user: currentUser } = useSelector((state) => state.auth);

  const dispatch = useDispatch();
  useEffect(() => {
    history.listen((location) => {
      dispatch(clearMessage()); // clear message when changing location
    });
  }, [dispatch]);

  useEffect(() => {
    if (currentUser) {
      setShowModeratorBoard(currentUser.roles.includes("ROLE_MODERATOR"));
      setShowAdminBoard(currentUser.roles.includes("ROLE_ADMIN"));
    }
  }, [currentUser]);

  useEffect(() => {
    DataService.getDevices().then(
      (devicesResponse) =>{
        DataService.getRacks().then(
          (racksResponse) =>{
            dispatch(setDc(DataService.getDc(racksResponse,devicesResponse)));
          }
        )
      }
    )
}, [dispatch]);
  const logOut = () => {
    dispatch(logout());
  };

  return (
    <div>
    <ModalProvider>
    <Router history={history}>
      <div>
        <nav className="navbar navbar-expand navbar-dark bg-dark">
          <Link to={"/"} className="navbar-brand">
            SimpliDC
            <img
                        alt=""
                        src={simplidc_logo}
                        width="30"
                        height="30"
                    />
          </Link>
          <div className="navbar-nav mr-auto">
            <li className="nav-item">
              <Link to={"/home"} className="nav-link">
                Home
              </Link>
            </li>

            {showModeratorBoard && (
              <li className="nav-item">
                <Link to={"/mod"} className="nav-link">
                  Moderator Board
                </Link>
              </li>
            )}

            {showAdminBoard && (
              <li className="nav-item">
                <Link to={"/admin"} className="nav-link">
                  Admin Board
                </Link>
              </li>
            )}

            {currentUser && (
              <li className="nav-item">
                <Link to={"/user"} className="nav-link">
                  User
                </Link>
              </li>
            )}
          </div>

          {currentUser ? (
            <div className="navbar-nav ml-auto">
              <li className="nav-item">
                <Link to={"/profile"} className="nav-link">
                  {currentUser.username}
                </Link>
              </li>
              <li className="nav-item">
                <a href="/login" className="nav-link" onClick={logOut}>
                  LogOut
                </a>
              </li>
            </div>
          ) : (
            <div className="navbar-nav ml-auto">
              <li className="nav-item">
                <Link to={"/login"} className="nav-link">
                  Login
                </Link>
              </li>

              <li className="nav-item">
                <Link to={"/register"} className="nav-link">
                  Sign Up
                </Link>
              </li>
            </div>
          )}
        </nav>
        <input className="" type="text" placeholder="Type any vaule to search in the DC..."/>

        <div className="container mt-3">

          <Switch>
            <Route exact path={["/", "/home"]} component={Home} />
            <Route exact path="/login" component={Login} />
            <Route exact path="/register" component={Register} />
            <Route exact path="/profile" component={Profile} />
            <Route path="/user" component={BoardUser} />
            <Route path="/mod" component={BoardModerator} />
            <Route path="/admin" component={BoardAdmin} />
            <Route path="/rack/:id" component={DetailedRackCard}/>
          </Switch>

        </div>
      </div>
    </Router>
    </ModalProvider>
    </div>
  );
};

export default App;

我在查看 Router 组件上的 react dev tools 时发现发生了一些奇怪的事情。这是刷新后的状态位置: 在此处输入图片说明

这是我单击路线(登录)后的同一对象: 在此处输入图片说明

我迫切需要帮助.... 是的,那是我整个应用程序中唯一的路由器。

谢谢!

1个回答

<Router/>state 来自您提供的 history 属性。您没有正确修改该 history 。错误的变异将在另一个文件中的某个位置。您似乎正在使用整个操作对象而不是仅使用 action.location 属性来调用 history.push()

<Router/> 组件与自定义 history 属性一起使用是一种高级设计模式,除非绝对必要,否则您通常要避免这种模式。我认为这里没有必要,至少对于这个特定文件中的代码来说没有必要。

我建议改用 <BrowserRouter/> (或 <HashRouter/> 等)。如果这样做,您将需要其他方法来解决 history.listen 订阅(旁注:您想使用清理函数在组件卸载时停止监听)。

您可以使用 useEffect 钩子来响应您从 useLocation 钩子访问的位置的变化。

const location = useLocation();

useEffect(() => {
  dispatch(clearMessage()); // clear message when changing location
}, [location, dispatch]);

如果您不想在第一次渲染时清除消息,您可以添加一些调度前进行额外检查。您可以使用 usePrevious 自定义钩子或类似钩子。在这里,我使用 useRef 来存储上一个位置。ref 的初始值是来自 useLocationlocation ,因此在第一次渲染时它们将相等。

const location = useLocation();

const locRef = useRef(location);

useEffect(() => {
  console.log(locRef.current, location);
  // will be equal on first render
  if (locRef.current !== location) {
    dispatch(clearMessage());
  }
  locRef.current = location;
}, [location, dispatch]);

如果您愿意,可以修改它以仅查看 pathname

Linda Paiste
2021-07-04