我有以下代码并且运行良好。
<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
我想了解为什么第二种方法不起作用。
当第一个
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
中。
在给定的渲染中,效果回调将按照声明的顺序运行。有了这个:
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。
const [contacts, setContacts] = useState(JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY)) || [])