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
Resolved! I had to move the checkTypaheadMatches function into a useEffect hook. This is what I did:
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 ofrecipTypeQ
after setting it.You may not need to call the
checkTypaheadMatches
inuseState
set function