71 lines
1.8 KiB
TypeScript
71 lines
1.8 KiB
TypeScript
import React, { useState, useCallback, useEffect } from 'react';
|
|
import { gql, useLazyQuery } from '@apollo/client';
|
|
import { Box, TextInput } from 'grommet';
|
|
import { FormSearch } from 'grommet-icons';
|
|
import { debounce } from 'lodash';
|
|
|
|
const SEARCH_ARTIST = gql`
|
|
query Artist($byName: String!) {
|
|
queryArtists(byName: $byName) {
|
|
name
|
|
}
|
|
}
|
|
`;
|
|
|
|
export const SearchBox = () => {
|
|
const [value, setValue] = useState('');
|
|
const [getArtist, { loading, data }] = useLazyQuery(SEARCH_ARTIST);
|
|
const [suggestions, setSuggestions] = useState(['']);
|
|
// TODO: Find a solution to have suggestions not showing when empty
|
|
|
|
// Debounce the database query, based on the following article:
|
|
// https://dev.to/reflexgravity/use-lodash-debouce-inside-a-functional-component-in-react-4g5j
|
|
const updateQuery = () => {
|
|
getArtist({ variables: { byName: value } });
|
|
};
|
|
|
|
const delayedQuery = useCallback(debounce(updateQuery, 500), [value]);
|
|
|
|
const handleChange = (e: any) => {
|
|
setValue(e.target.value);
|
|
};
|
|
|
|
useEffect(() => {
|
|
delayedQuery();
|
|
|
|
// Cancel previous debounce calls during useEffect cleanup.
|
|
return delayedQuery.cancel;
|
|
}, [value, delayedQuery]);
|
|
|
|
useEffect(() => {
|
|
// TODO: Maybe merge the two use effects?
|
|
if (data) {
|
|
const mapSuggestions: string[] = data.queryArtists.map(
|
|
(el: { name: string }) => {
|
|
return el.name;
|
|
},
|
|
);
|
|
const updatedSuggestions = mapSuggestions.slice(0, 5);
|
|
setSuggestions(updatedSuggestions);
|
|
}
|
|
}, [data]);
|
|
|
|
return (
|
|
<Box
|
|
as='section'
|
|
direction='row'
|
|
justify='center'
|
|
margin={{ vertical: 'large' }}
|
|
>
|
|
<TextInput
|
|
value={value}
|
|
onChange={handleChange}
|
|
placeholder='Type an artist name'
|
|
icon={<FormSearch color='plain' />}
|
|
dropHeight='large'
|
|
suggestions= {suggestions}
|
|
/>
|
|
</Box>
|
|
);
|
|
};
|