[英]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.