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

Ste*_*eve 2 local-storage reactjs next.js react-hooks

我有以下代码并且运行良好。<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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

为了完整起见,这是代码<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

Run Code Online (Sandbox Code Playgroud)

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

jul*_*ves 7

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


有几种方法可以处理它,但一种方法是contacts在将其值存储到 之前检查是否为空数组localStorage

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

这可以防止页面首次加载时contacts存储初始状态。localStorage