为什么本地存储不能与useEffect一起使用?

问题描述 投票:0回答:3

我有以下代码并且运行良好。

<AddContact />
是一个简单的组件,它呈现一个输入表单,该表单收集用户的姓名+电子邮件 - 为了完整起见,我在末尾附加了其代码。收集到的
contacts
数组存储在 localStorage 中,当我刷新页面时,它们只是重新加载。一切都好

import './App.css'
import { useState, useEffect } from 'react'

function App() {
    const LOCAL_STORAGE_KEY = 'contacts'

    const [contacts, setContacts] = useState(JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY)) || [])

    const addNewContact = (newContact) => {
        setContacts([...contacts, newContact])
    }

    useEffect(() => {
        console.table(contacts)
        localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(contacts))
    }, [contacts])

    return (
        <AddContact newContact={addNewContact} />
    )
}

export default App

我的问题是以下修订不起作用 - 每次刷新页面时,本地存储都会被擦除。但它看起来确实应该有效 - 我正在遵循在线教程,并且当讲师执行此操作时它正在工作。

import './App.css'
import { useState, useEffect } from 'react'

function App() {
    const LOCAL_STORAGE_KEY = 'contacts'

    const [contacts, setContacts] = useState([]) // changed line

    const addNewContact = (newContact) => {
        setContacts([...contacts, newContact])
    }

    useEffect(() => {
        console.table(contacts)
        localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(contacts))
    }, [contacts])

    // added
    useEffect(() => {
        const savedContacts = JSON.parse(
            localStorage.getItem(LOCAL_STORAGE_KEY)
        )
        if (savedContacts) {
            setContacts(savedContacts)
        }
    }, [])


    return (
        <AddContact newContact={addNewContact} />
    )
}

export default App

为了完整起见,这是

<AppContact />

的代码
import React, { Component } from 'react'

export class AddContact extends Component {
    state = {
        name: '',
        email: '',
    }

    updateState = (e) => {
        this.setState({ [e.target.name]: e.target.value })
    }

    addContact = (e) => {
        e.preventDefault()
        if (this.state.name === '' || this.state.email === '') {
            return
        }
        this.props.newContact(this.state)
    }

    render() {
        return (
            <div className='ui main'>
                <h2>Add Contact</h2>
                <form className='ui form' onSubmit={this.addContact}>
                    <div className='field'>
                        <label>Name</label>
                        <input
                            type='text'
                            name='name'
                            value={this.state.name}
                            placeholder='Name'
                            onChange={this.updateState}
                        />
                    </div>
                    <div className='field'>
                        <label>Email</label>
                        <input
                            type='text'
                            name='email'
                            value={this.state.email}
                            placeholder='Email'
                            onChange={this.updateState}
                        />
                    </div>
                    <button className='ui button blue' type='submit'>
                        Add
                    </button>
                </form>
            </div>
        )
    }
}

export default AddContact

我想了解为什么第二种方法不起作用。

reactjs react-hooks next.js local-storage
3个回答
5
投票

当第一个

addNewContact
运行时(如预期),您在调用
localStorage
时设置的值确实会存储在
useEffect
中。问题是,当您重新加载页面时,相同的
useEffect
会覆盖
localStorage
中的内容,因为状态被重置为空数组 (
[]
)。这会触发
useEffect
,其中
contacts
等于
[]
,并将其存储在
localStorage
中。


有几种方法可以处理它,但一种方法是在将其值存储到

contacts
之前检查
localStorage
是否为空数组。

useEffect(() => {
    console.table(contacts)
    if (contacts.length > 0) {
        localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(contacts))
    }
}, [contacts])

这可以防止页面首次加载时将

contacts
的初始状态存储在
localStorage
中。


1
投票

在给定的渲染中,效果回调将按照声明的顺序运行。有了这个:

useEffect(() => {
    console.table(contacts)
    localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(contacts))
}, [contacts])

// added
useEffect(() => {
    const savedContacts = JSON.parse(
        localStorage.getItem(LOCAL_STORAGE_KEY)
    )
    if (savedContacts) {
        setContacts(savedContacts)
    }
}, [])

在挂载时,第一个在第二个之前运行 - 您在第二个运行之前调用

localStorage.setItem
- 因此,当第二个运行时,存储已设置为
localStorage.getItem
状态的初始值,这是空数组。
要修复此问题,请颠倒它们的顺序,以便调用 

contacts

的那个先运行。

.getItem

也就是说,你的第一个方法

useEffect(() => { const savedContacts = JSON.parse( localStorage.getItem(LOCAL_STORAGE_KEY) ) if (savedContacts) { setContacts(savedContacts) } }, []); useEffect(() => { console.table(contacts) localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(contacts)) }, [contacts]);

看起来比带有空依赖数组的效果钩子好得多,IMO。


0
投票

const [contacts, setContacts] = useState(JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY)) || [])

© www.soinside.com 2019 - 2024. All rights reserved.