Reputation: 706
Using react-router-dom, react-redux, I tried to implement a website. The website has displayed the content based on the language setting using the redux store. When clicking the language area in Navbar, it callback changeLanguage
function, then it changes the state of language in the store and the website displays contents with changed language properly. However, when I click the other link '/home' or '/main' in the navbar, it is landing on the page with resetting the redux store. Could let me know how to deal with this issue?
languageSlice
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;
NavBar
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;
EventPage
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;
Upvotes: 2
Views: 1424
Reputation: 46873
The resetting of your store state is caused by a combination of two issues:
First, as you do not hydrating your React Store's state based on the current URL, you must somehow save and load your Store's state to preserve it between page loads.
You can emulate this problem by simply copying and pasting the URL to a new browser window; you'll notice the store state is reset. There are a number of ways to store state, and you may wish to use either sessionStorage which remains for the duration your app is on the browser's tab, or localStorage which remains until your app clears it.
Second, the reason you are getting page loads when you don't expect to, is that it appears you are not using React Router correctly.
You are using Bootstrap's Navbar Link, which behaves like a normal <a>
anchor tag. Click on the Nav.Link instructs your browser to make an HTTP GET call, and does a pageload which resets the store.
Instead you need to override the Bootstrap Nav Link component to instead use React Routers Link component, which will not do a page load, and instead load the correct React module.
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
Upvotes: 3