我的状态不断向其数组中添加空元素

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 的索引中。