Skip to content

Instantly share code, notes, and snippets.

@guimochila
Last active March 20, 2022 14:41
Show Gist options
  • Save guimochila/4fb10a0c1a858ddc6cd0596040394c94 to your computer and use it in GitHub Desktop.
Save guimochila/4fb10a0c1a858ddc6cd0596040394c94 to your computer and use it in GitHub Desktop.
Downshift and react-query
import { resetIdCounter, useCombobox } from 'downshift'
import Image from 'next/image'
import { useEffect, useRef, useState } from 'react'
import debounce from 'lodash/debounce'
import { DropDown, DropDownItem, SearchStyles } from './styled/DropDown'
import useSearch from '../hooks/useSearch'
function Search() {
resetIdCounter()
const [searchTerm, setSearchTerm] = useState<string | undefined>('')
const { data, isLoading, refetch } = useSearch(searchTerm)
const debouncedFindItem = useRef(debounce(refetch, 350))
const items = data?.searchTerms || []
const {
getMenuProps,
getInputProps,
getComboboxProps,
getItemProps,
highlightedIndex,
isOpen,
inputValue,
} = useCombobox({
items,
onSelectedItemChange() {
console.log('Selected Item change')
},
})
useEffect(() => {
const currentDebounceRef = debouncedFindItem.current
return () => currentDebounceRef.cancel()
}, [])
useEffect(() => {
async function updateSearch() {
setSearchTerm(inputValue)
await debouncedFindItem.current()
}
updateSearch()
}, [inputValue])
console.log(searchTerm)
return (
<SearchStyles>
<div {...getComboboxProps()}>
<input
{...getInputProps({
type: 'search',
placeholder: 'Search for an Item',
id: 'search',
className: isLoading ? 'loading' : '',
})}
/>
</div>
<DropDown {...getMenuProps()}>
{isOpen &&
items.map((item, index) => (
<DropDownItem
key={item.id}
{...getItemProps({ item })}
highlighted={index === highlightedIndex}
>
<Image
src={item.photo.image.publicUrlTransformed}
alt={item.name}
width={40}
height={40}
/>
{item.name}
</DropDownItem>
))}
{isOpen && !items.length ? (
<DropDownItem highlighted={false}>
Sorry, no items for {searchTerm}
</DropDownItem>
) : null}
</DropDown>
</SearchStyles>
)
}
export default Search
import { gql } from 'graphql-request'
import { useQuery } from 'react-query'
import { Product } from '../@types/graphql-generated'
import gqlClient from '../utils/requestClient'
const SEARCH_PRODUCTS_QUERY = gql`
query SEARCH_PRODUCTS_QUERY($searchTerm: String!) {
searchTerms: products(
where: {
OR: [
{ name: { contains: $searchTerm } }
{ description: { contains: $searchTerm } }
]
}
) {
id
name
photo {
image {
publicUrlTransformed
}
}
}
}
`
function useSearch(searchTerm: string | undefined) {
return useQuery<{ searchTerms: Product[] }>(
['search'],
async () => {
const items = await gqlClient.request(SEARCH_PRODUCTS_QUERY, {
searchTerm,
})
return items
},
{
enabled: false,
cacheTime: 0,
retry: false,
},
)
}
export default useSearch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment