我的状态不断向其数组中添加空元素
my state keeps adding empty elements into its array
我的 setter,对于 SetPersons,似乎无缘无故地不断向其数组中添加空元素。我试图在更新用户号码时立即更新我的 phone 号码列表,但它仍然使用旧号码。每当我应用可能使数字立即更新的逻辑时,它都会将空元素添加到我的数组中并且不会立即更新。这是每个单独组件的代码:
App.js
import { useEffect, useState, useRef} from 'react'
import PersonForm from './components/PersonForm'
import Display from './components/Display'
import Filter from './components/Filter'
import phoneService from './services/information'
const App = () => {
const [errorMessage, setErrorMessage] = useState('')
const [persons, setPersons] = useState('')
const [newName, setNewName] = useState('')
const [newNumber, setNewNumber] = useState('')
const [filter, setFilter] = useState('')
const [filterChecker, setFilterChecker] = useState('')
useEffect(() => {
phoneService.getAll()
.then(people => setPersons(people))
}, [])
const handleSubmit = (e) => {
e.preventDefault();
const copy = [...persons]
const foundNameOrNot = persons.some(el => el.name === newName)
const foundNumberOrNot = persons.some(el => el.number === newNumber)
const eachPersonsID = persons.map(person => person.id)
const newObj = {
name: newName,
number: newNumber,
id: Math.max(eachPersonsID) + 1
}
if (foundNameOrNot) {
if(window.confirm(`${newName} is added to phonebook, replace the old number with a new one.`)) {
const indexFinder = persons.filter(person => person.name === newName)
newObj.id = indexFinder[0].id
copy[indexFinder[0].id] = newObj
phoneService.update(indexFinder[0].id, newObj)
.then(res => {
setErrorMessage(`Successfully updated ${newName}s number`)
setPersons([copy])})
.catch(err => {
setErrorMessage(`Information on ${newName} has already been removed`)
setFilterChecker(filterChecker.filter(filter => filter !== newName))})
}
} else if (foundNumberOrNot) {
alert(`${newNumber} belongs to someone else`)
} else {
phoneService.create(newObj).then(res => setPersons([...persons, newObj]))
}
}
const handleFilter = (e) => {
console.log(persons)
setFilter(e.target.value)
const allNames = persons.map(person => person.name)
setFilterChecker(allNames.filter(name => name.toLowerCase().indexOf(filter.toLowerCase()) !== -1))
}
return (
<div>
<h1 className='error'>{errorMessage ? errorMessage : ''}</h1>
<h2>Phonebook</h2>
<Filter filter={filter} handleFilter={handleFilter}/>
<h2>add a new</h2>
<form onSubmit={handleSubmit}>
<PersonForm newName={newName} newNumber={newNumber} setNewName={setNewName} setNewNumber={setNewNumber}/>
<div>
<button type="submit">add</button>
</div>
</form>
<h2>Numbers</h2>
<Display filterChecker={filterChecker} persons={persons} setPersons={setPersons} setFilterChecker={setFilterChecker} errorMessage={errorMessage} setErrorMessage={setErrorMessage} />
</div>
)
}
export default App
Display.js
import phoneService from '../services/information'
import axios from 'axios'
import { useState } from 'react'
const handleDelete = (i, persons, setPersons, name2, setFilterChecker, errorMessage, setErrorMessage) => {
if (window.confirm(`delete ${name2} ?`)) {
const newArrayOfPeople = persons.filter(person => person.name !== name2)
const newArrayOfNames = newArrayOfPeople.map(person => person.name)
setFilterChecker(newArrayOfNames)
setPersons(newArrayOfPeople)
phoneService.remove(persons[i].id)
setErrorMessage(`You have successfully deleted ${name2} from the list.`)
setTimeout(() => {
setErrorMessage(null)
}, 5000)
}
}
const Display = ({filterChecker, persons, setPersons, setFilterChecker, errorMessage, setErrorMessage}) => {
const copy = [...persons]
const findNumbers = []
const findNames = []
for (let j = 0; j < copy.length; j++) {
if (copy[j]?.name && !findNames.includes(copy[j]?.name)) {
findNames.push(copy[j].name)
}
}
for (let i = 0; i < copy.length; i++) {
if (copy[i]?.number && !findNumbers.includes(copy[i]?.number)) {
findNumbers.push(copy[i]?.number)
}
}
if (filterChecker) {
return (
findNames.map((name, i) => <div><nobr key={name}>{name} {findNumbers[i]}</nobr> <button onClick={() => handleDelete(i, persons, setPersons, name, setFilterChecker, errorMessage, setErrorMessage)}>delete</button></div>)
)
} else {
return ''
}
}
export default Display
Filter.js
const Filter = ({filter, handleFilter}) => {
return <p>filter shown with <input value={filter} onChange={handleFilter}/></p>
}
export default Filter
PersonForm.js
import axios from 'axios';
import phoneService from '../services/information'
const PersonForm = ({newName, newNumber, setNewName, setNewNumber}) => {
return (
<div>
name: <input value={newName} onChange={(e) => setNewName(e.target.value)}/>
number: <input value={newNumber} onChange={(e) => setNewNumber(e.target.value)}/>
</div>
)
}
export default PersonForm
information.js
import axios from "axios"
const baseUrl = 'http://localhost:3002/numbers'
const getAll = () => {
const request = axios.get(baseUrl)
return request.then(response => response.data)
}
const create = newObject => {
const request = axios.post(baseUrl, newObject)
return request.then(response => response.data)
}
const update = (id, newObject) => {
const request = axios.put(`${baseUrl}/${id}`, newObject)
return request.then(response => response.data)
}
const remove = (id) => {
const request = axios.delete(`${baseUrl}/${id}`)
return request.then(res => res.data)
}
export default { getAll, create, update, remove, baseUrl }
我的json-服务器“db.json”
{
"numbers": [
{
"name": "uvaldo",
"number": "20",
"id": 6
},
{
"name": "uvaldo zumaya",
"number": "24",
"id": 7
},
{
"name": "uvaldo zumaya d",
"number": "26",
"id": 8
}
]
}
每当我尝试将“uvaldo”phone 数字更新为 22 时,它只会停留在 21 然后抛出错误,这张照片是在我点击“添加”之前以避免程序崩溃...
https://i.stack.imgur.com/CD2rh.png
您更新 persons
的逻辑存在问题。
试试这个:
const handleSubmit = (e) => {
...
const indexFinder = persons.findIndex(person => person.name === newName)
newObj.id = persons[indexFinder].id
copy[indexFinder] = newObj
phoneService.update(persons[indexFinder].id, newObj)
.then(res => {
setErrorMessage(`Successfully updated ${newName}s number`)
setPersons(copy)})
...
}
添加空元素的原因是用于放置newObj
的索引大于数组的大小:
copy[indexFinder[0].id] = newObj
另请注意,person.id
并不一定意味着它们位于数组 persons
的索引中。
我的 setter,对于 SetPersons,似乎无缘无故地不断向其数组中添加空元素。我试图在更新用户号码时立即更新我的 phone 号码列表,但它仍然使用旧号码。每当我应用可能使数字立即更新的逻辑时,它都会将空元素添加到我的数组中并且不会立即更新。这是每个单独组件的代码:
App.js
import { useEffect, useState, useRef} from 'react'
import PersonForm from './components/PersonForm'
import Display from './components/Display'
import Filter from './components/Filter'
import phoneService from './services/information'
const App = () => {
const [errorMessage, setErrorMessage] = useState('')
const [persons, setPersons] = useState('')
const [newName, setNewName] = useState('')
const [newNumber, setNewNumber] = useState('')
const [filter, setFilter] = useState('')
const [filterChecker, setFilterChecker] = useState('')
useEffect(() => {
phoneService.getAll()
.then(people => setPersons(people))
}, [])
const handleSubmit = (e) => {
e.preventDefault();
const copy = [...persons]
const foundNameOrNot = persons.some(el => el.name === newName)
const foundNumberOrNot = persons.some(el => el.number === newNumber)
const eachPersonsID = persons.map(person => person.id)
const newObj = {
name: newName,
number: newNumber,
id: Math.max(eachPersonsID) + 1
}
if (foundNameOrNot) {
if(window.confirm(`${newName} is added to phonebook, replace the old number with a new one.`)) {
const indexFinder = persons.filter(person => person.name === newName)
newObj.id = indexFinder[0].id
copy[indexFinder[0].id] = newObj
phoneService.update(indexFinder[0].id, newObj)
.then(res => {
setErrorMessage(`Successfully updated ${newName}s number`)
setPersons([copy])})
.catch(err => {
setErrorMessage(`Information on ${newName} has already been removed`)
setFilterChecker(filterChecker.filter(filter => filter !== newName))})
}
} else if (foundNumberOrNot) {
alert(`${newNumber} belongs to someone else`)
} else {
phoneService.create(newObj).then(res => setPersons([...persons, newObj]))
}
}
const handleFilter = (e) => {
console.log(persons)
setFilter(e.target.value)
const allNames = persons.map(person => person.name)
setFilterChecker(allNames.filter(name => name.toLowerCase().indexOf(filter.toLowerCase()) !== -1))
}
return (
<div>
<h1 className='error'>{errorMessage ? errorMessage : ''}</h1>
<h2>Phonebook</h2>
<Filter filter={filter} handleFilter={handleFilter}/>
<h2>add a new</h2>
<form onSubmit={handleSubmit}>
<PersonForm newName={newName} newNumber={newNumber} setNewName={setNewName} setNewNumber={setNewNumber}/>
<div>
<button type="submit">add</button>
</div>
</form>
<h2>Numbers</h2>
<Display filterChecker={filterChecker} persons={persons} setPersons={setPersons} setFilterChecker={setFilterChecker} errorMessage={errorMessage} setErrorMessage={setErrorMessage} />
</div>
)
}
export default App
Display.js
import phoneService from '../services/information'
import axios from 'axios'
import { useState } from 'react'
const handleDelete = (i, persons, setPersons, name2, setFilterChecker, errorMessage, setErrorMessage) => {
if (window.confirm(`delete ${name2} ?`)) {
const newArrayOfPeople = persons.filter(person => person.name !== name2)
const newArrayOfNames = newArrayOfPeople.map(person => person.name)
setFilterChecker(newArrayOfNames)
setPersons(newArrayOfPeople)
phoneService.remove(persons[i].id)
setErrorMessage(`You have successfully deleted ${name2} from the list.`)
setTimeout(() => {
setErrorMessage(null)
}, 5000)
}
}
const Display = ({filterChecker, persons, setPersons, setFilterChecker, errorMessage, setErrorMessage}) => {
const copy = [...persons]
const findNumbers = []
const findNames = []
for (let j = 0; j < copy.length; j++) {
if (copy[j]?.name && !findNames.includes(copy[j]?.name)) {
findNames.push(copy[j].name)
}
}
for (let i = 0; i < copy.length; i++) {
if (copy[i]?.number && !findNumbers.includes(copy[i]?.number)) {
findNumbers.push(copy[i]?.number)
}
}
if (filterChecker) {
return (
findNames.map((name, i) => <div><nobr key={name}>{name} {findNumbers[i]}</nobr> <button onClick={() => handleDelete(i, persons, setPersons, name, setFilterChecker, errorMessage, setErrorMessage)}>delete</button></div>)
)
} else {
return ''
}
}
export default Display
Filter.js
const Filter = ({filter, handleFilter}) => {
return <p>filter shown with <input value={filter} onChange={handleFilter}/></p>
}
export default Filter
PersonForm.js
import axios from 'axios';
import phoneService from '../services/information'
const PersonForm = ({newName, newNumber, setNewName, setNewNumber}) => {
return (
<div>
name: <input value={newName} onChange={(e) => setNewName(e.target.value)}/>
number: <input value={newNumber} onChange={(e) => setNewNumber(e.target.value)}/>
</div>
)
}
export default PersonForm
information.js
import axios from "axios"
const baseUrl = 'http://localhost:3002/numbers'
const getAll = () => {
const request = axios.get(baseUrl)
return request.then(response => response.data)
}
const create = newObject => {
const request = axios.post(baseUrl, newObject)
return request.then(response => response.data)
}
const update = (id, newObject) => {
const request = axios.put(`${baseUrl}/${id}`, newObject)
return request.then(response => response.data)
}
const remove = (id) => {
const request = axios.delete(`${baseUrl}/${id}`)
return request.then(res => res.data)
}
export default { getAll, create, update, remove, baseUrl }
我的json-服务器“db.json”
{
"numbers": [
{
"name": "uvaldo",
"number": "20",
"id": 6
},
{
"name": "uvaldo zumaya",
"number": "24",
"id": 7
},
{
"name": "uvaldo zumaya d",
"number": "26",
"id": 8
}
]
}
每当我尝试将“uvaldo”phone 数字更新为 22 时,它只会停留在 21 然后抛出错误,这张照片是在我点击“添加”之前以避免程序崩溃...
https://i.stack.imgur.com/CD2rh.png
您更新 persons
的逻辑存在问题。
试试这个:
const handleSubmit = (e) => {
...
const indexFinder = persons.findIndex(person => person.name === newName)
newObj.id = persons[indexFinder].id
copy[indexFinder] = newObj
phoneService.update(persons[indexFinder].id, newObj)
.then(res => {
setErrorMessage(`Successfully updated ${newName}s number`)
setPersons(copy)})
...
}
添加空元素的原因是用于放置newObj
的索引大于数组的大小:
copy[indexFinder[0].id] = newObj
另请注意,person.id
并不一定意味着它们位于数组 persons
的索引中。