【问题标题】:Updating React state after axios PUT request without having to reload page在 axios PUT 请求后更新 React 状态而无需重新加载页面
【发布时间】:2022-01-11 06:07:02
【问题描述】:

在我当前的应用程序中,如果用户尝试输入具有不同号码的现有名称,它会提示用户是否要使用新号码更新该条目。如果是,则使用 axios PUT 请求更新条目。我的问题是我只能通过重新加载页面(它在db.json 上成功更新)来更改前端,而不是在用户确认后立即更新。在我的useEffect 方法中,我尝试添加[persons] 作为第二个参数,它似乎有效,但发现它无限循环GET 请求。我在删除条目时有类似的功能,所以我确定它一定是必须添加到setPersons

更新方法

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)
}

其他代码

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>
  )
}

【问题讨论】:

  • 请提供完整的组件代码
  • @HDM91 我添加了用于显示条目的方法和添加条目的方法,请告诉我如果需要更多我认为应该是所有相关代码
  • 在哪里呈现新的人员条目并调用添加条目?在应用组件中?
  • @HDM91 我添加了更多代码,条目列表由DisplayPersons组件呈现
  • 为什么你没有在这里更新那个人:setPersons() //something here

标签: javascript reactjs axios


【解决方案1】:

这里的解决方案有点棘手但可行。你需要把你的逻辑分成两部分:

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 )
} , [])

【讨论】:

    【解决方案2】:

    能够使用有效的map 方法

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

    【讨论】:

      猜你喜欢
      • 2021-04-09
      • 1970-01-01
      • 2019-03-13
      • 2017-10-06
      • 2019-07-10
      • 2019-08-09
      • 2020-07-05
      • 2014-02-21
      • 1970-01-01
      相关资源
      最近更新 更多