如何在 react 中监听 localstorage 值的变化?

IT技术 reactjs events local-storage addeventlistener
2021-04-20 03:13:01

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

我不知道在 header 组件中在哪里听。

// 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>
    );
   }  
}

//登录组件(登录.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>

        )
    }

}
2个回答

请注意两点

  1. storage事件仅在同一个应用程序在两个浏览器选项卡中打开时才起作用(它用于在同一应用程序的不同选项卡之间交换信息)。当两个组件显示在同一页面上时,不会触发存储事件

  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});
        });
    

这是一个简单的例子

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

我们可以在反应中使用 redux 来实现这一点吗
2021-06-03 03:13:01
当我在 2 个标签中打开时它工作正常。但我希望它在单个标签中收听
2021-06-08 03:13:01
在单个选项卡中打开时,不会触发存储事件。存储事件的目标是在选项卡之间交换信息。要在单个页面上的组件之间交换信息,请使用提升状态reactjs.org/docs/lifting-state-up.htmlSothis.state.auth将在LoginComponentand 的父组件中HeaderComponent并将作为道具传递
2021-06-08 03:13:01
是的,redux 也管理状态,但集中进行。我建议从反应状态开始,但要提升它。它比使用 redux 更容易
2021-06-12 03:13:01

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

我有一个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 was successful, update local storage
   localStorage.setItem("name",someName)


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