【问题标题】:How to listen to localstorage value changes in react?react如何监听localstorage值的变化?
【发布时间】:2019-11-01 17:59:48
【问题描述】:

我想在用户登录时显示一个按钮。如果用户没有登录,那么我不会显示按钮。当用户登录时,我将设置本地存储值。当我在登录组件中设置本地存储时,标题组件必须监听该事件并显示按钮。我正在使用 addEventListener 进行监听。但它没有监听。

我不知道在 header Component 中听哪里。

// HeaderComponent(header.js):

class HeaderComponent extends Component {
    componentDidMount(){
        if(typeof window!='undefined'){
            console.log(localStorage.getItem("token"));
            window.addEventListener("storage",function(e){
               this.setState({ auth: true});
            })
        }
    } 
    render() {

    return (
        <div className="header">
            <div className="container">
                <div className="header-content">
                    <img src={logo} alt="logo"></img>
                    <div className="nav-links" >
                        <ul >
                            <li>Home</li>
                            <li>About</li>
                            <li>Services</li>
                            <li><NavLink activeClassName="active" to="/upload" >Upload</NavLink></li>
                            <li><NavLink activeClassName="active" to="/signup"> Sign Up</NavLink></li>


                           { this.state.auth? <li onClick={this.onLogout}>Logout</li> :null}

                        </ul>
                    </div>
                </div>
            </div>

        </div>
    );
   }  
}

//loginComponent(login.js)

class LoginComponent extends Component {
    constructor(props) {
        super(props);
        this.onSubmit = this.onSubmit.bind(this);
    }
    onSubmit(event) {
        const data = {
            username: document.getElementById('name').value,
            password: document.getElementById('password').value
        }
        axios.post(`http://localhost:4000/user/login`, data).then(res => {
            this.props.history.push("/");
            localStorage.setItem("token",res.data.token);
            localStorage.setItem("auth",true);
        }).catch(err => console.log(err));
    }


    render() {
        return (
            <section class="log-in">
                <div class="card-col">
                    <form>
                        <h3>LOG IN</h3>
                        <div class="form-controls">
                            <input id="name" type="text" placeholder="username" class="input"></input>
                        </div>
                        <div class="form-controls">
                            <input id="password" type="password" placeholder="password" class="input"></input>
                        </div>
                        <button type="submit" onClick={this.onSubmit} class="button" >Log in</button>
                    </form>
                </div>

           </section>

        )
    }

}

【问题讨论】:

  • 这两个组件是否共享一个共同的父级?如果是这样,让LoginComponent 在该父级中设置auth 状态,然后将其作为prop 传递给HeaderComponent
  • 如果它们在一个组件中,只需调用 setState。但是如果它们在单独的组件中,您可以向 reducer 发送一个操作并将包含按钮的组件连接到 redux。如果您感到困惑,请随时询问!
  • @Lobster Confusing.. 你能提供示例代码吗

标签: reactjs events local-storage addeventlistener


【解决方案1】:

我发现了一个非常糟糕的黑客来完成这个:

我有一个Toolbar 和一个Login 组件,其中Toolbar 组件侦听localStorage 中的更改,并在Login 组件更新本地存储时显示登录用户名(如果身份验证成功)。

工具栏组件

(类似于您的情况下的Header 组件)

const [loggedInName, setLoggedInName] = useState(null);

    useEffect(() => {
        console.log("Toolbar hi from useEffect")
        setLoggedInName(localStorage.getItem('name') || null)
        window.addEventListener('storage', storageEventHandler, false);

    }, []);

    function storageEventHandler() {
        console.log("hi from storageEventHandler")
        setLoggedInName(localStorage.getItem('name') || null)
    }

    function testFunc() {  
        console.log("hi from test function")
        storageEventHandler();
    }

为您的Toolbar 组件添加一个隐藏按钮。点击此隐藏按钮将调用testFunc() 函数,该函数将在本地存储更新后立即更新登录用户的名称。

   <button style={{ display: 'none' }} onClick={testFunc} id="hiddenBtn">Hidden Button</button>

现在,在您的 Login 组件中

   .
   .
   .
   //login was successful, update local storage
   localStorage.setItem("name",someName)


   //now click the hidden button using Javascript
   document.getElementById("hiddenBtn").click();
   .

【讨论】:

    【解决方案2】:

    请注意两点

    1. storage 事件仅在同一应用程序在两个浏览器选项卡中打开时有效(它用于在同一应用程序的不同选项卡之间交换信息)。存储事件will not fire when both components shown on the same page

    2. 添加事件监听器时,您传递的是function(),而不是数组函数。 function() 不捕获 this 所以你应该明确地 bind(this) 或将其更改为箭头函数。

      例如

      window.addEventListener("storage",(function(e){
             this.setState({ auth: true});
          }).bind(this));
      

      或者用箭头函数做

      window.addEventListener("storage",(e) => {
             this.setState({ auth: true});
          });
      

    这里是简单的example

    请务必在两个选项卡中打开它(同一个链接)。将值存储在一个选项卡中,然后在另一个选项卡中查看此值。

    【讨论】:

    • 当我在 2 个标签中打开时它工作正常。但我希望它在单个标签中收听
    • 在单个选项卡中打开时不会触发存储事件。存储事件的目标是在选项卡之间交换信息。要在单个页面上的组件之间交换信息,请使用提升状态 reactjs.org/docs/lifting-state-up.html。所以this.state.auth 将在LoginComponentHeaderComponent 的父组件中,并将作为道具传递下来
    • 我们可以在 react 中使用 redux 来实现吗
    • 是的,redux 也管理状态,但集中进行。我建议从反应状态开始,但将其提升。比使用 redux 更容易
    猜你喜欢
    • 2021-08-13
    • 1970-01-01
    • 2013-04-18
    • 1970-01-01
    • 1970-01-01
    • 2012-06-25
    • 2021-07-02
    • 2021-05-29
    • 1970-01-01
    相关资源
    最近更新 更多