skip to Main Content

I’m building a typahead search that listens to the state of the input and renders a list of search results that include the input. But my function checkTypaheadMatches, which sets the state for the results that match the input state, is one step behind. For some reason, in this function, the input state is one step behind.

However, if I console log the input state OUTSIDE of the function, it is not behind. I’m confused because I thought I had my onChange function setup currently on my input. What is wrong? How can I fix it?

Here is my App.jsx (it renders the Header component, which renders my SearchBar component.)

import { useState } from 'react'
import { Outlet, useNavigate } from "react-router-dom"
import Header from "./components/Header"

const App = () => {
  const navigate = useNavigate()

  const validRecipTypes = ["medical doctor", "doctor of osteopathy", "doctor of podiatric medicine", "physician assistant", "nurse practitioner", "certified registered nurse anesthetist", "doctor of dentistry"]

  const [recipTypeQ, setRecipTypeQ] = useState("")
  const [typaheadMatches, setTypaheadMatches] = useState(validRecipTypes)
  const [searchResults, setSearchResults] = useState([])

  const checkTypaheadMatches = () => {
    let matches = []
    for (const recipient_type of validRecipTypes) {
        if (recipient_type.includes(recipTypeQ.toLowerCase())) {
            matches.push(recipient_type)
        }
    }

    console.log("Am I fixed yet?: ", recipTypeQ) // <-- this is one step behind!

    setTypaheadMatches(matches)
  }

  const onRecipTypeQChange = (e) => {
    setRecipTypeQ(e.target.value, checkTypaheadMatches()) // <-- did I do this right?
  }

  const handleSearch = (e) => {
    // search function
  }

  return <>
    <div className="App w-screen p-8">
      <Header 
        onRecipTypeQChange={onRecipTypeQChange} 
        handleSearch={handleSearch} 
        recipTypeQ={recipTypeQ}
        typaheadMatches={typaheadMatches}
        setTypaheadMatches={setTypaheadMatches}
        />
      <Outlet context={[
        searchResults, setSearchResults,
        validRecipTypes
      ]} />
    </div>
  </>
}

export default App

My SearchBar.jsx

import TypaheadMatchesDisplay from "./TypaheadMatchesDisplay";

const SearchBar = ({onRecipTypeQChange, handleSearch, typaheadMatches}) => {
    return <div className="flex items-center gap-6 px-4 border-2 border-green-500 relative">
        <label htmlFor="search_form" className="text-lg font-medium">Search:</label>

        <form data-test="search-form" onSubmit={handleSearch} method="GET" id="search_form">

            <input onChange={onRecipTypeQChange} type="text" id="recipTypeQ" name="recipTypeQ" required mindocLength="1" placeholder="search by recipient type..."/>

            <TypaheadMatchesDisplay typaheadMatches={typaheadMatches}/>

            <button data-test="submit-button" type="submit" form="search_form" value="Submit">Submit</button>
        </form>
    </div>
}

export default SearchBar

2

Answers


  1. Chosen as BEST ANSWER

    Resolved! I had to move the checkTypaheadMatches function into a useEffect hook. This is what I did:

     useEffect(checkTypaheadMatches, [recipTypeQ])
    
      const onRecipTypeQChange = (e) => {
        setRecipTypeQ(e.target.value)
      }
    

  2. It is one step behind because you are checking in the wrong place. The job of the checkTypaheadMatches function is to find the matches, but not to set the value. So you should check the value of recipTypeQ after setting it.

    You may not need to call the checkTypaheadMatches in useState set function

    const onRecipTypeQChange = (e) => {
      checkTypaheadMatches();
      setRecipTypeQ(e.target.value);
      // check the value of recipTypeQ here
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search