简体   繁体   中英

React hooks: Can't update state inside function component

I'm new to React and am trying to figure out how to make a phonebook. I've gotten quite far but I'm having an issue I can't solve. I'm using React Hooks.

Everything works fine, except for when I call the setNewNumber('') and setNewName('') functions at the end of addPerson() , just before the filteredEntries const. I want to reset the input fields in the form to empty strings ( '' ) once the other code inside addPerson() is done running, but it seems like the two functions are never called since the value for newName and newNumber don't change to '' (instead they keep the values the user added). However, my other useState functions ( setPersons() and setFilteredPersons() ) work inside addPerson() ...

I've tried reading the documentation and asking around but haven't found a solution. I'd be very grateful for any clues/help!

import React, { useState } from 'react'
import Person from './components/Person'

const App = () => {
  const [ persons, setPersons ] = useState([
    { name: 'Cat', number: '111' },
    { name: 'Dog', number: '222' },
    { name: 'Horse', number: '333' },
    { name: 'Owl', number: '444' }
  ]) 
  const [filteredPersons, setFilteredPersons] = useState([...persons])
  const [ newName, setNewName ] = useState('')
  const [ newNumber, setNewNumber ] = useState('')

  const addPerson = (event) => {
    event.preventDefault()

    const createPerson = () => {
      const personObject = {
        name: newName,
        number: newNumber,
      }
      setPersons([...persons, personObject])
      setFilteredPersons([...persons, personObject]) //varför går det inte att bara köra [...persons?]
    }

    const upperCaseNewName = newName.toUpperCase()
    let doubleName
    persons.map(person => {
      const upperCasePerson = person.name.toUpperCase()
      if(upperCaseNewName === upperCasePerson) {
        doubleName = upperCasePerson
      }
      return doubleName
    })

    if (doubleName === undefined) {
      createPerson()
    } else if(doubleName === upperCaseNewName) {
      alert(`${newName} is already in the phonebook`)
    }

    setNewName('')
    setNewNumber('')
  }

  const filterEntries = event => {
      let filtered = persons.filter(person => {
        return person.name.toUpperCase().indexOf(event.target.value.toUpperCase()) !== -1
      })
    setFilteredPersons(filtered)
  }

  const renderPersons = () => filteredPersons.map(person =>
    <Person key={person.name} name={person.name} number={person.number}/>
  )

  return (
    <div>
      <h2>Phonebook</h2>
      <p>Filter entries:</p> <input onChange={(event) => filterEntries(event)}/>
      <form>
        <div>
          name: <input onChange={(event) => setNewName(event.target.value)}/>
          <br/>
          phone: <input onChange={(event) => setNewNumber(event.target.value)}/>
        </div>
        <div>
          <button type="submit" onClick={addPerson}>add</button>
        </div>
      </form>
      <h2>Numbers</h2>
      {renderPersons()}
    </div>
  )
}

export default App

The person component at the top just contains this code:

import React from 'react'

const Person = (props) => {
    return(
        <>
        <p>{props.name} {props.number}</p>
        </>
    )
}

export default Person

Your components are not actually tied to your state values. You need them to be "controlled." Check out the docs for more examples:)

https://reactjs.org/docs/forms.html#controlled-components

<input value={newName} onChange={event => setNewName(event.target.value)} />

The reset is working correctly. What you forgot to do is add the value to each input. Without the value attribute the input is considered an uncontrolled component . By the sounds of it, you're looking to control the value via code.

Change

<div>
  name: <input onChange={event => setNewName(event.target.value)} />
  <br />
  phone: <input onChange={event => setNewNumber(event.target.value)} />
</div>

to

<div>
  name: <input value={newName} onChange={event => setNewName(event.target.value)} />
  <br />
  phone: <input value={newNumber} onChange={event => setNewNumber(event.target.value)} />
</div>

Codesandbox Demo

You have missed adding value attribute to input and thus your component is not the "Controlled" component.

You can read more here .

Changes needed

<input
   value={newName}
   onChange={event => setNewName(event.target.value)}
/>
<br />
phone:
<input
   value={newNumber}
   onChange={event => setNewNumber(event.target.value)}
/>

Codesandbox Link: https://codesandbox.io/s/crimson-frog-ecp98

Hope this Helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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