【问题标题】:How to make localStorage reactive in react?如何使 localStorage 在反应中反应?
【发布时间】:2021-12-20 17:24:39
【问题描述】:

我正在使用 localStorage 来保存登录时的用户数据。我已将其保存为“jwt_data”。 我在 saperate js 文件上创建了一个函数来检索该数据作为

export const auth = () => {
  if(localStorage.getItem('jwt_data')){
    return JSON.parse(localStorage.getItem('jwt_data'))
  }else{
    return false
  }
}

我有一个导航栏组件,它可以与 做出反应。我想在用户注销后隐藏它并在我登录后显示。 我用代码作为

const auth_user = auth()
........
<>
{auth_user ? (// if logged in..... )  : (// if user is logged out........)

</>

确实奏效了。但问题是它不是被动的。我需要重新加载网站才能看到效果。

我也试过用其他的比如

const [auth_user, setAuth_user] = useState(false)
useEffect(() => {
 if(auth()) {setAuth_user(true)}    
 else {setAuth_user(false)}
})

与之前的结果相同。 我不知道我错在哪里。其他人建议使用redux之类的东西,这对我的头脑和我的简单应用来说太复杂了。

我的 app.js 看起来像这样

import React from 'react';
import Nav from './Nav';
import Home from './Home';
import Login from './Login';
import Logout from './Logout';


function App() {
  return (
    <div className="App">
      <Router>
     <Router>
      <Nav/>
      <Routes>
        <Route exact path="/home" element={<Home/>}/>
        <Route exact path="/login" element={<Login/>}/>
        <Route exact path="/logout" element={<Logout/>}/>
      </Routes>
      </Router>
    </div>
  );
}

登录后,我搬家了,这样做时,我想删除导航栏中所有仅显示已通过身份验证的内容,就像在这种情况下和一般其他情况下一样。

我在这里缺少什么吗? 感谢您的友好回答。

【问题讨论】:

    标签: javascript reactjs local-storage


    【解决方案1】:

    所以在这种情况下你需要 useContext。

    在你的 app.js 中

    import React, { useContext } from "react";
    
    export const AuthContext = React.createContext(null);
    
    function App() {
    
      const [authContext, setAuthContext] = useState(localStorage.getItem("auth"));
    
      return (
        <AuthContext.Provider value={authContext, setAuthContext}>
          <Router>
            <Nav/>
            <Routes>
              <Route exact path="/home" element={<Home/>}/>
              <Route exact path="/login" element={<Login/>}/>
              <Route exact path="/logout" element={<Logout/>}/>
            </Routes>
          </Router>
        </AuthContext.Provider>
      );
    }
    

    然后在你的 Nav.js 中

    import React, { useContext } from "react";
    import { AuthContext } from "./App.js"
    
    function Nav() {
    
      const [authContext, setAuthContext] = useContext(AuthContext);
    
      return (
        authContext
          ? /*Navbar with user stuff*/
          : /*Empty Navbar */
      )
    }
    

    在您的登录组件中:

    import React, { useContext } from "react";
    import { AuthContext } from "./App.js"
    
    function Login() {
    
      const [authContext, setAuthContext] = useContext(AuthContext);
    
      const login = () => {
        const jwt = "jwt"; // fetch your jwt
        localStorage.setItem("auth", jwt)
        setAuthContext(jwt);
      }
    
      return (
        <div>Login form</div>
      )
    }
    

    然后退出:

    import React, { useContext } from "react";
    import { AuthContext } from "./App.js"
    
    function Logout() {
    
      const [authContext, setAuthContext] = useContext(AuthContext);
    
      const logout = () => {
        localStorage.setItem("auth", null)
        setAuthContext(null);
      }
    
      return (
        <button onClick={logout}>Logout button</button>
      )
    }
    

    【讨论】:

    • 谢谢这解决了问题。谢谢你。有一些错误代码请更正。 :)
    • 我发现它有效。但是我发现了奇怪的行为,如果我再次刷新它会意外出现。
    【解决方案2】:

    我认为这里的问题是您将localStorage 视为您的状态,这在 React 空间中并不完全正确。为了让您的组件更新,您需要将此信息保持在您的组件可以订阅的状态。 React 状态(useState)或全局状态(redux、context 等)。

    那么您的语言环境存储密钥将是初始化此状态的一种方式(例如刷新时)。因此,当登录状态发生变化时,您必须同时更新它们。

    由于您想让事情保持简单,最好的方法是在您的 App 组件中创建一个 loggedIn 状态,然后将 loggedIn 状态(Nav 组件)或 setLoggedIn 设置器(登录/注销组件)来更新它。

    您可以找到有关如何创建使用 localeStorage 的反应挂钩的示例,例如 this one。如果您使用链接中的useLocalStorage 或任何其他类似的实现,您可以在下面找到您应用的代码。

    import React from 'react';
    import Nav from './Nav';
    import Home from './Home';
    import Login from './Login';
    import Logout from './Logout';
    import useLocaleStorage from 'somewhere'
    
    
    function App() {
      const [loggedIn, setLoggedIn] = useLocalStorage('jwt_data', false);
    
      return (
        <div className="App">
          <Router>
         <Router>
          <Nav loggedIn={loggedIn} /> // and hide what's need to be hidden
          <Routes>
            <Route exact path="/home" element={<Home/>}/>
            <Route exact path="/login" element={<Login setLoggedIn={setLoggedIn} />}/>
            <Route exact path="/logout" element={<Logout setLoggedIn={setLoggedIn} />}/>
          </Routes>
          </Router>
        </div>
      );
    }
    

    但是,随着您的应用变得越来越复杂,您可能会重新考虑将其保持在内部反应状态并改用上下文,以避免从您的 App 组件向其子组件钻取道具。

    【讨论】:

    • 谢谢。 :) 我用过 useContext
    猜你喜欢
    • 1970-01-01
    • 2018-12-03
    • 2020-09-30
    • 2022-07-08
    • 2021-03-24
    • 2020-02-03
    • 2020-03-24
    • 2022-06-10
    • 1970-01-01
    相关资源
    最近更新 更多