简体   繁体   English

在 axios PUT 请求之后更新 React state 而无需重新加载页面

[英]Updating React state after axios PUT request without having to reload page

On my current application, if a user tries to enter an existing name that has a different number, it will prompt the user if they want to update that entry with the new number.在我当前的应用程序中,如果用户尝试输入具有不同号码的现有名称,它将提示用户是否要使用新号码更新该条目。 If yes, the entry is updated using an axios PUT request.如果是,则使用 axios PUT 请求更新条目。 My issue is that I can only get it to change on the front end by reloading the page (it updates successfully on db.json ) instead of it updating immediately after the user confirms.我的问题是我只能通过重新加载页面(它在db.json上成功更新)来让它在前端进行更改,而不是在用户确认后立即更新。 On my useEffect method I tried adding [persons] as the second argument and it seemed to work, but found out that it loops the GET requests infinitely.在我的useEffect方法中,我尝试添加[persons]作为第二个参数,它似乎有效,但发现它无限循环 GET 请求。 I have a similar function for when deleting an entry so I'm sure it must be something that has to be added to setPersons我有一个类似的 function 用于删除条目时,所以我确定它必须是必须添加到setPersons的东西

Update methods更新方法

const addEntry = (event) => {
    event.preventDefault();
    const newPersonEntry = {
      name: newName,
      number: newNumber,
    }
    const all_names = persons.map(person => person.name.toUpperCase())
    const all_numbers = persons.map(person => person.number)
    const updatedPerson = persons.find(p => p.name.toUpperCase() === newName.toUpperCase())

    const newPerson = { ...updatedPerson, number: newNumber };
    if (newName === '') {
      alert('Name entry cannot be blank')
      return
    }
    if (newNumber === '') {
      alert('Number entry cannot be blank')
      return
    }
    if (all_numbers.includes(newNumber)) {
      alert('That number already exists')
      return
    }
    if (newNumber.length < 14) {
      alert('Enter a valid number')
      return
    }
    if (all_names.includes(newName.toUpperCase())) {
      if (window.confirm(`${newName} already exists, replace number with the new one?`)) {
        console.log(`${newName}'s number updated`)
        personService
          .update(updatedPerson.id, newPerson)
          .then(res => {
            setPersons() //something here
          })
        return
      }
      return
    }

    personService
      .create(newPersonEntry)
      .then(person => {
        setPersons(persons.concat(person))
        setNewName('')
        setNewNumber('')
      })
  }

//PUT exported as personService
const update = (id, newObject) => {
    const request = axios.put(`${baseURL}/${id}`,newObject)
    return request.then(response => response.data)
}

Other code其他代码

const App = () => {
  const [persons, setPersons] = useState([])
  
  useEffect(() => {
    personService
      .getAll()
      .then(initialPersons => {
        setPersons(initialPersons)
      })
  }, [])
...

//Display method
const filteredNames = persons.filter(person => person.name.toLowerCase().includes(filter.toLowerCase()))

  const row_names = () => {
    return (
      filteredNames.map(person =>
        <p key={person.id}>{person.name} {person.number} <button onClick={() => handleDelete(person)}>delete</button></p>));
  }

...
//Render 
return (
    <div>
      <h2>Phonebook</h2>
      <h2>Search</h2>
      <SearchFilter value={filter} onChange={handleFilterChange} />
      <h2>Add Entry</h2>
      <Form onSubmit={addEntry}
        name={{ value: newName, onChange: handleNameChange }}
        number={{ value: newNumber, onChange: handleNumberChange }}
      />
      <h2>Numbers</h2>
      <DisplayPersons persons={row_names()} />
    </div>
  )
}

The solution here is a little bit tricky but doable.这里的解决方案有点棘手但可行。 You need to split your logic into two parts like this:您需要将逻辑分成两部分,如下所示:

const [dataChanged , setDataChanged] = useState(false)

useEffect(()=>{
   // Rest of your logic here
} , [dataChanged])

useEffect(()=>{
   // Your logic will run only one time
   // on Success we change the dataChanged state so the other useEffect will 
   // run basically you can run the rest of your logic in the other 
   // useEffect so the infinite loop won't happen
   // setDataChanged( (prev) => !prev )
} , [])

Was able to use map method that worked能够使用有效的map方法

personService
   .update(updatedPerson.id, newPerson)
   .then(res => {
      setPersons(persons.map(p => p.id !== updatedPerson.id ? p : res))
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM