admin管理员组

文章数量:1392002

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 './ponents/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 ponent at the top just contains this code:

import React from 'react'

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

export default Person

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 './ponents/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 ponent at the top just contains this code:

import React from 'react'

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

export default Person
Share Improve this question asked Oct 15, 2019 at 15:17 JumpyWizardJumpyWizard 251 silver badge6 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 3

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

https://reactjs/docs/forms.html#controlled-ponents

<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 ponent. 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 ponent is not the "Controlled" ponent.

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!

本文标签: javascriptReact hooks Can39t update state inside function componentStack Overflow