如何在 React.js 中使用 react-router-dom 保持 App() 级别状态不重置?

Posted

技术标签:

【中文标题】如何在 React.js 中使用 react-router-dom 保持 App() 级别状态不重置?【英文标题】:How do I keep App() level state from resetting with react-router-dom in React.js? 【发布时间】:2021-06-04 12:19:35 【问题描述】:

我有一个钩子可以改变我的应用程序的背景颜色。我希望在浏览网站时背景颜色保持不变,但路由器将此状态重置回其原始 useState 的“白色”。如何正确实施?

使用 create-react-app 创建。

已编辑以显示最小可重现示例:

import React,  useState  from 'react';
import  Route, Switch, BrowserRouter  from 'react-router-dom';
import './App.css';

export default function App() 
  const [color, setColor] = useState('white');

  function changeBackground(value) 
    setColor(value);
  ;

  return (
    <div className=color>
      <BrowserRouter>
        <Navbar changeBackground=changeBackground />
      </BrowserRouter>
    </div>
  );
;

function Navbar(props) 

  return (
    <div>
      <button onClick=() => props.changeBackground('red')>
        Change Background Color
      </button>
      <div>
        <a href="/page1">Page 1</a>
      </div>
      <div>
        <a href="/page2">Page2</a>
      </div>
      <Switch>
        <Route exact path="/page1"><Page1 /></Route>
        <Route exact path="/page2"><Page2 /></Route>
      </Switch>
    </div>
  );
;

function Page1() 

  return (
    <div>
      Page 1
    </div>
  );
;

function Page2() 

  return (
    <div>
      Page 2
    </div>
  );
;
/* App.css */
.white 
  background-color: white;

.red 
  background-color: red;

添加最小可重现示例之前的先前代码:

import React,  useState  from 'react';
import  Route, Switch, BrowserRouter  from 'react-router-dom';
import './App.css';
import './assets/fonts/fonts.css';
import Navbar from './components/Navbar';
import Design from './components/Design';
import Develop from './components/Develop';
import Else from './components/Else';
import DesignTest from './pages/DesignTest';

function App() 
  const [backgroundColor, setBackgroundColor] = useState('white');


  function changeBackground(value) 
    setBackgroundColor(value);
  ;


  return (
    <div className=`w-screen min-h-screen $backgroundColor`>
      /* <Router> */
      <Navbar changeBackground=changeBackground />
      <BrowserRouter>
        <Switch>
          <Route exact path="/"></Route>
          <Route exact path="/design"><Design /></Route>
          <Route exact path="/develop"><Develop /></Route>
          <Route exact path="/else"><Else /></Route>
          <Route exact path="/design/test"><DesignTest /></Route>
        </Switch>
      </BrowserRouter>
    </div>
  );


export default App;

function Navbar(props) 

  return (
  <div className="w-screen h-screen inline-grid grid-cols-12 grid-rows-6 tuffyBold tracking-widest">
            <div className="row-start-1 row-end-3 col-start-1 col-end-7 text-right mt-auto mb-auto text-5xl">
              TITLE
         </div>
              <div className="row-start-3 row-end-4 col-start-7 col-end-13 test-left mt-auto mb-auto text-4xl">
                <a href="/design">
                  DESIGN
                </a>
              </div>
              <div className="row-start-4 row-end-5 col-start-7 col-end-13 test-left mt-auto mb-auto text-4xl">
                <a href="/develop">
                  DEVELOP
                </a>
              </div>
              <div className="row-start-5 row-end-7 col-start-7 col-end-13 test-left mt-auto mb-auto text-4xl">
                <a href="/else">
                  EVERY<br />THING<br />ELSE
                </a>
              </div>
            <div className="row-start-1 row-end-3 col-start-7 col-end-13 mt-auto mb-auto ml-auto mr-auto">
              <div className="circle white" onClick=() => props.changeBackground('white')></div>
            </div>
            <div className="row-start-3 row-end-4 col-start-1 col-end-7 mt-auto mb-auto ml-auto mr-auto">
              <div className="circle yellow" onClick=() => props.changeBackground('yellow')></div>
            </div>
            <div className="row-start-4 row-end-5 col-start-1 col-end-7 mt-auto mb-auto ml-auto mr-auto">
              <div className="circle blue" onClick=() => props.changeBackground('blue')></div>
            </div>
            <div className="row-start-5 row-end-6 col-start-1 col-end-7 mt-auto mb-auto ml-auto mr-auto">
              <div className="circle dark" onClick=() => props.changeBackground('dark')></div>
            </div>
          </div>
          
            );


export default Navbar;
.yellow 
  background-color: #CDB900;
  color: black;

.blue 
  background-color: #009CCD;
  color: black;

.dark 
  background-color: #4B394E;
  color: white;

.white 
  background-color: white;
  color: black;

【问题讨论】:

你能分享Navbar吗? 这并不能解决您的问题,但如果它只是要调用 setBackgroundColor,则您不需要 changeBackground 函数。您可以直接传递 setBackgroundColor。 【参考方案1】:

当我单击导航栏以更改路线时,我遇到了相同的应用程序状态刷新问题。原来是因为没有使用react router提供的Link组件造成的。

就我而言,我使用的是引导导航栏组件。我从引导站点获得的代码创建了这样的导航栏链接:

<Nav.Link href="/home">Home</Nav.Link>

通过“href”的导航是这里的问题。所以为了克服这个问题,我将 Nav.Link 包裹在 LinkContainer 中。这使我可以从 Nav.Link 中删除 href,并使用 LinkContainer 中的“to”属性提供了路由 url。

<LinkContainer to="/home">
    <Nav.Link>Home</Nav.Link>
</LinkContainer>

为了使用 LinkContainer,我必须安装并导入它。

npm install react-router-bootstrap


import  LinkContainer  from "react-router-bootstrap";

【讨论】:

【参考方案2】:

我发现了我的问题。我使用 &lt;a href="/#"&gt; 而不是从 react-router-dom 导入 Link,导致整个页面重新渲染。这是我想要的版本:

import React,  useState  from 'react';
import  Route, Switch, BrowserRouter, Link  from 'react-router-dom';
import './App.css';

export default function App() 
  const [color, setColor] = useState('white');

  function changeBackground(value) 
    setColor(value);
  ;

  return (
    <div className=color>
      <BrowserRouter>
        <Navbar changeBackground=changeBackground />
      </BrowserRouter>
    </div>
  );
;

function Navbar(props) 

  return (
    <div>
      <button onClick=() => props.changeBackground('red')>
        Change Background Color
      </button>
      <div>
        <Link to="/page1">Page 1</Link>
      </div>
      <div>
        <Link to="/page2">Page2</Link>
      </div>
      <Switch>
        <Route exact path="/page1"><Page1 /></Route>
        <Route exact path="/page2"><Page2 /></Route>
      </Switch>
    </div>
  );
;

function Page1() 

  return (
    <div>
      Page 1
    </div>
  );
;

function Page2() 

  return (
    <div>
      Page 2
    </div>
  );
;
/* App.css */
.white 
  background-color: white;

.red 
  background-color: red;

【讨论】:

这个答案对我有用。我用它来解决我遇到的同样的问题。就我而言,问题是由于使用了使用 href 的引导导航栏组件而发生的。我还提供了我的解决方案作为答案,以防它对其他人有帮助。【参考方案3】:

似乎有什么东西触发了重新渲染整个应用程序。可能 React 开发者工具可以帮助你在代码中找到那个地方。

我创建了一个孤立的例子 - https://codesandbox.io/s/solitary-wood-8oi66?fontsize=14&hidenavigation=1&theme=dark&file=/src/App.js

在这个例子中,钩子中的颜色值也保存到浏览器LocalStorage中,并用作第一次渲染的默认值,因此可以在重新加载页面后保持背景颜色。也许这就是您想要实现的目标。但我不确定。

  const defaultColor = localStorage.getItem("bgColor");
  const [backgroundColor, setBackgroundColor] = useState(
    defaultColor || "white"
  );

  function changeBackground(value) 
    setBackgroundColor(value);
    localStorage.setItem("bgColor", value);
  

【讨论】:

【参考方案4】:

因为您的Navbar 在路由器组件之外,这意味着您单击的所有内容实际上是在重新加载页面,而不是被 react-router 捕获。在浏览器路由器中移动导航栏组件:

  return (
    <div className=`w-screen min-h-screen $backgroundColor`>
      /* <Router> */

      <BrowserRouter>
        <Navbar changeBackground=changeBackground />
        <Switch>
          <Route exact path="/"></Route>
          <Route exact path="/design"><Design /></Route>
          <Route exact path="/develop"><Develop /></Route>
          <Route exact path="/else"><Else /></Route>
          <Route exact path="/design/test"><DesignTest /></Route>
        </Switch>
      </BrowserRouter>
    </div>
  );

【讨论】:

感谢您的关注。我进行了更改,但每当我在网站上的任何位置导航时,背景颜色仍会变回“白色”。 你能创建一个minimal, reproducible example吗? 更新了最小可重复的例子。

以上是关于如何在 React.js 中使用 react-router-dom 保持 App() 级别状态不重置?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 React.js 中使用 Google 字体?

如何在 node.js 中导入 font-awesome 以在 react.js 中使用?

如何在 React.js 中使用 JavaScript 修改 CSS

React JS:如何在 react-spring 中使用响应式样式

如何在 react.js 中使用 json

如何在 React.js 中使用 react-router-dom 保持 App() 级别状态不重置?