简体   繁体   中英

Delay in filter input basic reactJS search function

I've made a basic phonebook application for an online exercise that allows you to save people's names and phone numbers to a phone book. There is also a search input that allows you to filter results based on name. It all works, however, one weird thing that I can't figure out is that the filter is always delayed by one character, the state isn't updated immediately when the user inputs a character into the search bar?

For example:

if I type 'J' into the search it will filter for ''

if I then type 'a' so now 'Ja' is in the search bar it will filter for 'J'

if I then backspace the 'a' so now 'J' is in the search bar it will filter for 'Ja'

and so on... the filter is always one step behind.

I'm new to state's and can't seem to fix it. Can anyone help me out? thanks. (also if there is any other constructive critique to my code that would improve it I'm very open and appreciative of it)

my Code:

const phonebook = [
  {
    id: 1,
    details: {
      name: 'Jim',
      number: '55 748 192'
    }
  },
  {
    id: 2,
    details: {
      name: 'Jason',
      number: '55 111 192'
    }
  },
  {
    id: 3,
    details: {
      name: 'Jonesy',
      number: '55 983 122'
    }
  },
  {
    id: 4,
    details: {
      name: 'Jack',
      number: '0408 729 000'
    }
  },

]


const App = (props) => {

  const [bookData, setBookData] = useState(props.props)
  const [newName, setNewName] = useState('')
  const [newNumber, setNewNumber] = useState('')
  const [theFilter, setTheFilter] = useState('')
  const [namesToShow, setNamesToShow] = useState(bookData.map(person => person.details))

  const [errorMessage, setErrorMessage] = useState('')

  console.log('the filter', theFilter, namesToShow)

  const addNumber = (event) => {
    event.preventDefault()
    const numberObject = {
      id: bookData.length + 1,
      details: {
        name: newName,
        number: newNumber,
      }
    }
    if(numberObject.details.name !== "" && numberObject.details.number !== '') {
      setBookData(bookData.concat(numberObject))
      setNewName('')
      setNewNumber('')
      setErrorMessage('')
    } else {
      if(numberObject.details.name === "" && numberObject.details.number === "") {
        setErrorMessage('You must enter a name and number!!')
      } else if(numberObject.details.number === "") {
        setErrorMessage('You must enter a number!!')
      } else {
        setErrorMessage('You must enter a name!!!')
      }
    }
  }

  const handleFilterChange = (event) => {
    setTheFilter(event.target.value)
    console.log(theFilter)
    if(theFilter === '') {
      setNamesToShow(bookData.map(person => person.details))
      console.log('help')
    } else {
      console.log('bookData', bookData.map(person => person.details))
      setNamesToShow(bookData.map(person => person.details).filter(person => person.name.includes(theFilter)))
      console.log('filter', theFilter)
      console.log('potential namestoshow?', bookData.map(person => person.details).filter(person => person.name.includes(theFilter)))
      console.log('namestoshow', namesToShow)
    }
  }

  const handleNameChange = (event) => {
    setNewName(event.target.value)
  }

  const handleNumberChange = (event) => {
    setNewNumber(event.target.value)
  }

  return (
    <>
      <h1>Phonebook</h1>
      <div>
        <input value={theFilter} onChange={handleFilterChange} placeholder='Search for a name' />
        {namesToShow.map(person => (
          <p>{person.name}: {person.number}</p>
          ))}
      </div>
      <form>
        <input value={newName} onChange={handleNameChange} placeholder='Enter a name...'/>
        <input value={newNumber} onChange={handleNumberChange} placeholder='Enter a number...'/>
        <button type='submit' onClick={addNumber}>Save</button>
      </form>
      <div>
        {errorMessage}
      </div>
    </>
  )
}



ReactDOM.render(
  <App props={phonebook} />,
  document.getElementById('root')
)

This is because useState updates is batched. When you set a new state it is not set immediately. So the best approach in a functional component would be to use a useEffect hook that depends on this variable. For example:

useEffect(() => {
  doSomeJob(theFilter);
}, [theFilter])

Where [theFilter] is an array of variables which change should fire that effect.

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