【问题标题】:Switch themes when local storage changes onClick in react当本地存储发生变化时切换主题 onClick 反应
【发布时间】:2021-07-05 01:35:01
【问题描述】:

我正在尝试根据存储在本地存储中的主题键在深色和浅色之间切换主题。我有一个功能可以在单击时更改本地存储中的键值。但是,单击不会呈现组件,用户必须刷新页面才能看到更新的主题。

这里是 App.js 组件,检查本地存储,如果本地存储为 null,则设置默认主题:

import React from  'react';


const App = () => {
  
    return (
        <Router>
            <div className=
                     {
                         window.localStorage.getItem('theme') === null ?
                             window.localStorage.setItem('theme','theme-light'):
                             window.localStorage.getItem('theme')
                     }>
                <Switch>
       
                    <Route exact path='/'> <LandingPage/> </Route>
                    <Route exact path='/register'> <RegisterPage/> </Route>
                    <Route exact path='/login'> <LoginPage/> </Route>
                    
                </Switch>
            </div>
        </Router>
    );
}

export default App;

这里的函数包含一个在本地存储中设置新主题的函数,onclick键值在本地存储中确实发生了变化,但是页面不会重新渲染,需要用户手动刷新页面从本地存储中获取更新的主题。

我希望主题在点击时打开。

import React,{useState, useEffect} from 'react'
import {RiMoonLine} from 'react-icons/ri'
import {FiSun} from 'react-icons/fi'


const UserProfilePromoter = () =>{

    const [user, setUser] = useState({})

    const items = { ...localStorage }
    const localUser = JSON.parse(window.localStorage.getItem('user'))

  useEffect(()=>{
      if(localUser){
          const userId = localUser.id
          const userFullName = `${localUser.firstname} ${localUser.lastname}`
          const username = localUser.username
          const avatar = localUser.avatar
          setUser({
              ...user,
              id: userId,
              name: userFullName,
              username: username,
              avatar: avatar,
              theme: items.theme
          })
      }

  },[])


    const onThemeChange = (e) => {
        let currentTheme = window.localStorage.getItem('theme')

        console.log(currentTheme)

        if(currentTheme === 'theme-light') {
            window.localStorage.setItem('theme', 'theme-dark')
            setUser({
                ...user,
                theme: 'theme-dark'
            })
        } else {
            window.localStorage.setItem('theme', 'theme-light')
            setUser({
                ...user,
                theme: 'theme-light'
            })
        }
    }

 

    return(
        <>
            {
                localUser &&
                <div className="profilePrompterContainer">
                    <div className="ProfilePrompterAvatarWrapper" role="button">
                        <div className="ProfilePrompterAvatar ProfilePrompterWrapper">
                            <img src={user.avatar}
                                 className="profilePrompterUserAvatar" alt={`sosums_user_${user.name}`}
                            />
                        </div>
                    </div>
                    <div className="ProfilePrompterNameTag" role="button" >
                        <div className="userFullNameContainer">
                            <div className="userFullNameText">{user.name}</div>
                        </div>
                        <div className="profilePrompterUsernameText size12">
                            {!user.username ? <div className='setUserNameText'> @Set Username </div>: user.username}
                        </div>
                    </div>
                    <div className="ProfilePrompterBtnGroup" onClick={onThemeChange}>
                        <button type="button" className="iconBtn">
                            <div className="iconContentWrapper">
                                <span className='iconContent'>
                                    {
                                        window.localStorage.getItem('theme')=== 'theme-light' ? <RiMoonLine/>:
                                            <FiSun/>
                                    }
                                </span>
                            </div>
                        </button>
                    </div>
                    
                </div>
            }
            {
                !localUser && <div className="noLocalUser"> </div>
            }

        </>
    )
}

export default UserProfilePromoter

【问题讨论】:

  • useEffect 不监听本地存储的变化
  • 要重新渲染一个 React 组件,你只需要更新一个状态,但这次不同,要重新加载应用程序,你必须使用 window.location.reload() 强制重新加载,这在用户刷新时是一样的该页面,您将需要找到使用 reload() 的位置

标签: javascript reactjs local-storage


【解决方案1】:

更新
由于您想重新渲染父 App 组件,您需要将其更新功能作为道具发送给子 UserProfilePromoter 组件。

//Parent App component
export default function App() {
  const [themeUpdated, setThemeUpdated] = useState(false);

  const updateAppComponent = () => {
    setThemeUpdated(!themeUpdated);
  };

  const getClass = () => {
    return localStorage.getItem('theme');
  };

  return (
    <div className={getClass()}>
      <h1>Hello StackBlitz!</h1>
      <Sample updateAppComponent={updateAppComponent} />
    </div>
  );
}
//Child sample component
export default function Sample(props) {
  const { updateAppComponent } = props;
  const [themeToggle, setThemeToggle] = useState(false);

  const update = () => {
    setThemeToggle(!themeToggle);
    const themeName = themeToggle ? 'theme-red' : 'theme-blue';
    localStorage.setItem('theme', themeName);
    updateAppComponent();
  };

  return (
    <div>
      <h1>Sample works!</h1>
      <button onClick={update}>Update</button>
    </div>
  );
}

注意:我使用不同的组件名称和逻辑来更新主题,但您将通过示例了解想法。

Working Stackblitz

原创

const [user, setUser] = useState({})

useEffect(()=>{
  if(localUser){
      ...
  }

},[user]) //Add user state here

详情

useEffect 第一个参数是根据第二个参数执行n次的方法。

  1. 如果省略第二个参数
useEffect(()=>{
 //this method gets invokes for every change in the component
})
  1. 如果将第二个参数添加为空数组([])
useEffect(()=>{
 //this method gets invoked exactly 1 time same as componentDidMount
})
  1. 如果您将第二个参数添加为带有用户状态的数组 ([user])
useEffect(()=>{
 //this method gets invoked when user state changes
})

观看此video 或阅读此官方article

【讨论】:

  • 如果我将用户添加为第二个参数,它会不断重新渲染并引发错误:index.js:1 警告:超出最大更新深度。当组件调用 setState inside effect 时,可能会发生这种情况,但 useEffect 要么没有依赖数组,要么依赖项之一在每次渲染时发生变化。但只有当用户点击切换主题按钮时,用户状态才会更新。
  • @TayyabRahman 我想你想重新渲染App 组件,对吧?因为那是你应用主题类的地方
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-06
  • 1970-01-01
  • 2021-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多