简体   繁体   English

在浏览器上访问/重新加载/或返回页面时,如何使主题 state 持久化?

[英]How to make theme state be persistent when visiting/reloading/or going back a page on the browser?

How can I get my light/dark theme to be persistently saved as a state when a user reloads, visits a new page, or presses back on a browser, etc... Right now it's very inconsistent.当用户重新加载、访问新页面或按回浏览器等时,如何将我的浅色/深色主题永久保存为 state 等......现在它非常不一致。

Here is the index.js where I set up my theme.这是我设置主题的 index.js。 I wrap it around my components.我将它包裹在我的组件周围。

index.js

import { ThemeProvider, CssBaseline } from "@material-ui/core";
import { createMuiTheme } from "@material-ui/core";

const MyThemeContext = React.createContext({});

export function useMyThemeContext() {
    return useContext(MyThemeContext);
  }
  
function MyThemeProvider(props) {
  const [isDarkMode, setIsDarkMode] = useState(false);

  const theme = useMemo(
    () =>
      createMuiTheme({
        palette: {
          type: isDarkMode ? 'dark' : 'light',
        },
      }),
    [isDarkMode]
  );

  return (
    <ThemeProvider theme={theme}>
      <MyThemeContext.Provider value={{ isDarkMode, setIsDarkMode }}>
        {props.children}
      </MyThemeContext.Provider>
    </ThemeProvider>
  );
}


const routing = (
    <Router>
        <React.StrictMode>
            <MyThemeProvider>
                <CssBaseline />
                    <Header />
                    <Switch>
                        <Route exact path="/" component={App} />
                        <Route path="/register" component={Register} />
                        <Route path="/login" component={Login} />
                        <Route path="/logout" component={Logout} />
                        <Route path="/dash/:slug" component={Bucket} />
                        <Route path="/create" component={CreateBucket}/>
                    </Switch>
                    <Footer />
            </MyThemeProvider>
        </React.StrictMode>
    </Router>
);

ReactDOM.render(routing, document.getElementById('root'));




I use a switch that activates the state of the theme, it's located in my header.我使用一个开关来激活主题的 state,它位于我的 header 中。 header.js

import React from 'react';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import CssBaseline from '@material-ui/core/CssBaseline';
import { makeStyles } from '@material-ui/core/styles';
import { NavLink } from 'react-router-dom';
import Link from '@material-ui/core/Link';
import Button from '@material-ui/core/Button';
import Switch from '@material-ui/core/Switch';
import { useMyThemeContext } from '../index';


const useStyles = makeStyles((theme) => ({
    appBar: {
        borderBottom: `1px solid ${theme.palette.divider}`,
    },
    link: {
        margin: theme.spacing(1, 1.5),
    },
    toolbarTitle: {
        flexGrow: 1,
    },
}));


function Header() {
    const classes = useStyles();

    const {isDarkMode, setIsDarkMode} = useMyThemeContext();

    return (
        <React.Fragment>
            <CssBaseline />
            <AppBar
                position="static"
                color="default"
                elevation={0}
                className={classes.appBar}
            >
                <Toolbar className={classes.toolbar}>
                    <Switch
                        checked={isDarkMode}
                        onChange={() => setIsDarkMode(!isDarkMode)}
                    />
                </Toolbar>
            </AppBar>
        </React.Fragment>
    );
}

export default Header;

How can I fix the inconsistency with the state not being saved?如何解决与未保存 state 的不一致问题? Thank you for the help!感谢您的帮助!

you would use localStorage to persist state in memory, passing a key name.您将使用localStorage将 state 保存在 memory 中,并传递一个键名。 on app reload your initial state would come from that value stored in localStorage , if it's not set then !!在应用程序上重新加载您的初始 state 将来自存储在localStorage中的那个值,如果它没有设置那么!! will ensure the value is false rather than null将确保该值为false而不是null

Also pass to Provider a function that updates state and also set the new value to localStorage .还将更新 state 的 function 传递给Provider并将新值设置为localStorage this way you don't need remember to set the value at localStorage every place you consume the setIsDarkMode这样你就不需要记住在你使用setIsDarkMode的每个地方都设置localStorage的值

// if it's not set in localStorage value is null, then !! will set as false
const initialState = !!JSON.parse(localStorage.getItem('theme'))

function MyThemeProvider(props) {
  const [isDarkMode, setIsDarkMode] = useState(initialState);

  // you pass another function where you persist the value to localStorage
  // given your code you may just create a toggle function where you don't need to pass a value. but you can change it to receive an argument
  const toggleDarkMode = () => {
    setIsDarkMode(themeMode => {
      localStorage.setItem('theme', !themeMode)
      return !themeMode
    })
  }

  const theme = useMemo(
    () =>
      createMuiTheme({
        palette: {
          type: isDarkMode ? 'dark' : 'light',
        },
      }),
    [isDarkMode]
  );

  return (
    <ThemeProvider theme={theme}>
      <MyThemeContext.Provider value={{ isDarkMode, toggleDarkMode }}>
        {props.children}
      </MyThemeContext.Provider>
    </ThemeProvider>
  );
}

and at your Header you extract toggleDarkMode instead:在你的Header你提取toggleDarkMode代替:

function Header() {
    const classes = useStyles();

    const {isDarkMode, toggleDarkMode} = useMyThemeContext();

    return (
        <React.Fragment>
            <CssBaseline />
            <AppBar
                position="static"
                color="default"
                elevation={0}
                className={classes.appBar}
            >
                <Toolbar className={classes.toolbar}>
                    <Switch
                        checked={isDarkMode}
                        onChange={toggleDarkMode}
                    />
                </Toolbar>
            </AppBar>
        </React.Fragment>
    );
}

export default Header;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用浏览器后退按钮时如何强制重新加载页面? - How to force reloading a page when using browser back button? 使用 VueJs/Vuex 重新加载页面时保持持久状态 - Maintaining persistent state when reloading a page using VueJs/Vuex 在(持久切换)jQuery中访问其他页面时的持久内容 - Persistent content when visiting other page in (persistent toggle) jQuery 单击浏览器后退按钮时如何维护页面状态? - How to maintain the page state when browser back button is clicked? 重新加载页面时,使浏览器转到页面顶部 - Make browser go to top of page when reloading page 回访时恢复页面内容 - Recover page content when visiting back jQuery 脚本的元素在返回到浏览器上的页面时起作用,但在刷新时不起作用 - Elements of the jQuery scripts work when going back to a page on the browser but not on refresh 通过重新加载第1页,然后再次将其滚动回浏览器,使浏览器返回 - Make browser to go back by reloading page 1st and then scrolling it back again too 在地图中添加一个点,而无需返回到控制器或重新加载页面 - Add a point in the map without going back to a controller or reloading the page 防止转到浏览器后退按钮上的上一页 - Prevent going to the previous page on browser back button
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM