在 React 中路由其他组件时重置 redux 存储

Posted

技术标签:

【中文标题】在 React 中路由其他组件时重置 redux 存储【英文标题】:Resetting the redux store when routing other components in React 【发布时间】:2021-07-28 04:28:18 【问题描述】:

使用 react-router-dom、react-redux,我尝试实现一个网站。该网站已根据使用 redux 商店的语言设置显示内容。点击导航栏中的语言区域时,回调changeLanguage函数,然后改变商店的语言状态,网站正确显示改变语言的内容。但是,当我单击导航栏中的其他链接“/home”或“/main”时,它会登陆页面,resetting the redux store。可以告诉我如何处理这个问题吗?

语言切片

import  createSlice  from "@reduxjs/toolkit";

export const languageSlice = createSlice(
  name: "language",
  initialState: 
    language: "Fr",
  ,
  reducers: 
    getLanguage: (state, action) => 
      return state;
    ,
    changeLanguage: (state, action) => 
      if (action.payload == "En") 
        return 
          ...state,
          language: "Fr",
        ;
       else 
        return 
          ...state,
          language: "En",
        ;
      
    ,
  ,
);

export const  getLanguage, changeLanguage  = languageSlice.actions;
export default languageSlice.reducer;

store.js

import  configureStore  from "@reduxjs/toolkit";
import languageSlice from "./languageSlice";

export default configureStore(
  reducer: 
    languageSlice: languageSlice,
  ,
);

LanguageService.js

import  getLanguage, changeLanguage  from "../app/languageSlice";

export const changeLan = (dispatch, language) => 
  dispatch(changeLanguage(language));
;

export const getLan = (dispatch) => 
  dispatch(getLanguage());
;

Index.jsx

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import store from "./app/store";
import  Provider  from "react-redux";
import "bootstrap/dist/css/bootstrap.min.css";

ReactDOM.render(
  <React.StrictMode>
    <Provider store=store>
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById("root")
);

reportWebVitals();

App.jsx

import "./App.css";
import React,  useEffect  from "react";
import  MainPage  from "./MainPage";
import  Home  from "./Home";
import  Switch, BrowserRouter, Redirect, Route  from "react-router-dom";
import Navbar from "./layout/NavBar";
import Event from "./staticPages/Event";
import  getLan  from "./service/LanguageService";
import  useDispatch, useSelector  from "react-redux";

function App() 
  const dispatch = useDispatch();
  const language = useSelector((state) => state.languageSlice.language);

  useEffect(() => 
    getLan(dispatch);
    console.log(language);
  , [language]);

  return (
    <div
      className=" ml-auto mr-auto"
      style=
        width: "80%",
      
    >
      <BrowserRouter>
        <Navbar />
        <Switch>
          <Route exact path="/home" render=() => <Home /> />
          <Route exact path="/main" render=() => <MainPage /> />
          <Route exact path="/event" render=() => <Event /> />         
          <Route component=() => <h3>Page is not found!</h3> />
        </Switch>
        <Footer />
      </BrowserRouter>
    </div>
  );


export default App;

导航栏

import  Nav, Navbar, NavDropdown, Image  from "react-bootstrap";
import React,  useState, useEffect  from "react";
import  useDispatch, useSelector  from "react-redux";
import  changeLan, getLan  from "../service/LanguageService";

const NavBar = () => 
  const dispatch = useDispatch();
  const language = useSelector((state) => state.languageSlice.language);

  const changeLanguage = () => 
    changeLan(dispatch, language);
  ;


  return (
    <>
      <Navbar collapseOnSelect expand="sm">
        <Navbar.Brand href="/home">
         Home
        </Navbar.Brand>
        <Nav onSelect=changeLanguage>
          <Nav.Item>
            <Nav.Link href="#">language</Nav.Link>
          </Nav.Item>
        </Nav>
        <Navbar.Toggle aria-controls="responsive-navbar-nav" />        
          <Navbar.Collapse id="responsive-navbar-nav">
            <Nav className="ml-auto" light="true">             
              <NavDropdown title="Events" id="nav-dropdown1">
                <NavDropdown.Item href="/event">Latest Events</NavDropdown.Item>
              </NavDropdown>   
              <Nav.Item>
                <Nav.Link href="/main">Access Survey Portal</Nav.Link>
              </Nav.Item>           
            </Nav>
          </Navbar.Collapse>
      </Navbar>
    </>
  );
;

export default NavBar;

事件页面

import React from "react";
import  useSelector  from "react-redux";

const Event = () => 
  const language = useSelector((state) => state.languageSlice.language);

  return (
    <>
      language != "En" ? (
        <div className="area">
          <section
            className="product_landing_welcome_area product_landing jarallax my-auto"
            id="home"
            style= backgroundColor: "#008fac" 
          >
            <div className="container h-100">
              <div className="row align-items-center">
                <div className="col-sm col-md-12 col-lg-12 text-center">
                  <div
                    className="welcome_text_area m-top-3"
                    style=
                      width: "100%",
                      paddingBottom: "35px",
                      paddingTop: "35px",
                      marginBottom: "0px",
                    
                  >
                    <h3 className="fonts-shadow-into-light text-white">
                      <b>Latest Events</b>
                    </h3>
                  </div>
                </div>
              </div>
            </div>
          </section>
        </div>
      ) : (
        <div className="area">
          <section
            className="product_landing_welcome_area product_landing jarallax my-auto"
            id="home"
            style= backgroundColor: "#008fac" 
          >
            <div className="container h-100">
              <div className="row align-items-center">
                <div className="col-sm col-md-12 col-lg-12 text-center">
                  <div
                    className="welcome_text_area m-top-3"
                    style=
                      width: "100%",
                      paddingBottom: "35px",
                      paddingTop: "35px",
                      marginBottom: "0px",
                    
                  >
                    <h3 className="fonts-shadow-into-light text-white">
                      <b>Événements récents</b>
                    </h3>
                  </div>
                </div>
              </div>
            </div>
          </section>
        </div>
      )
    </>
  );
;

export default Event;

【问题讨论】:

【参考方案1】:

您的商店状态的重置是由两个问题的组合引起的:

首先,由于您没有根据当前 URL 对 React Store 的状态进行水合,因此您必须以某种方式保存和加载 Store 的状态以在页面加载之间保留它。

您可以通过简单地将 URL 复制并粘贴到新的浏览器窗口来模拟此问题;您会注意到商店状态已重置。存储状态的方法有很多种,您可能希望使用 sessionStorage(在您的应用位于浏览器选项卡上时保留)或 localStorage(在您的应用清除它之前保留)。

其次,您在不期望的情况下获得页面加载的原因是您似乎没有正确使用 React Router。

您正在使用 Bootstrap 的导航栏链接,其行为类似于普通的 &lt;a&gt; 锚标记。单击 Nav.Link 会指示您的浏览器进行 HTTP GET 调用,并执行页面加载以重置商店。

相反,您需要覆盖 Bootstrap Nav Link 组件以使用 React Routers Link 组件,该组件不会进行页面加载,而是加载正确的 React 模块。

https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage https://reactrouter.com/web/api/Link

【讨论】:

感谢您的评论。顺便说一句,您能否解释一下“相反,您需要覆盖 Bootstrap Nav Link 组件以使用 React Routers Link 组件,该组件不会进行页面加载,而是加载正确的 React 模块。”详细点? 将 NavBar 组件中的 Nav.Link 组件替换为 react-router-dom 中的 Link 组件。即&lt;Link to="/main"&gt;Access Survey Portal&lt;/Link&gt; 感谢@Alan,感谢您的评论,这(***.com/questions/54843302/…)解决了我的问题。 明白了。这个&lt;Nav.Link as=Link to="/main" &gt;Access Survey Portal&lt;/Nav.Link&gt; 对于 NavDropdown,您可以使用 React Routers history.push 以编程方式在点击处理程序内重定向。要访问历史记录,您可以使用 useHistory 挂钩。

以上是关于在 React 中路由其他组件时重置 redux 存储的主要内容,如果未能解决你的问题,请参考以下文章

React中路由中的redux和redux拓展

在将 react-router 5 与 redux 7 一起使用时,react-router <Link> 在转到新路由后不会重置状态

React,redux 组件不会在路由更改时更新

如何重置 react-redux 的值?

React Redux 状态将在使用 Nginx 更改路由时初始化

Redux dispatch 导致组件本地状态重置