spoti-search/src/components/SearchBox.tsx

83 lines
2.0 KiB
TypeScript
Raw Normal View History

2020-07-22 18:46:13 +00:00
import React, { useState, useCallback, useEffect } from 'react';
import { gql, useLazyQuery } from '@apollo/client';
2020-07-22 15:16:49 +00:00
import { Box, TextInput } from 'grommet';
import { FormSearch } from 'grommet-icons';
2020-07-22 18:46:13 +00:00
import { debounce } from 'lodash';
import { Artists, Artist } from '../interfaces';
const QUERY_ARTIST_ALBUMS = gql`
2020-07-22 18:46:13 +00:00
query Artist($byName: String!) {
queryArtists(byName: $byName) {
name
image
id
albums {
name
image
id
}
2020-07-22 18:46:13 +00:00
}
}
`;
2020-07-22 15:16:49 +00:00
export const SearchBox = () => {
2020-07-23 08:56:03 +00:00
const [inputValue, setInputValue] = useState('');
const [getArtists, { data }] = useLazyQuery(QUERY_ARTIST_ALBUMS);
const [artists, setArtists] = useState<Artists | undefined>(undefined);
const [suggestions, setSuggestions] = useState<string[] | undefined>(
undefined,
);
2020-07-22 18:46:13 +00:00
// 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 = () => {
2020-07-23 08:56:03 +00:00
getArtists({ variables: { byName: inputValue } });
2020-07-22 18:46:13 +00:00
};
2020-07-23 08:56:03 +00:00
const delayedQuery = useCallback(debounce(updateQuery, 500), [inputValue]);
2020-07-22 18:46:13 +00:00
const handleChange = (e: any) => {
2020-07-23 08:56:03 +00:00
setInputValue(e.target.value);
2020-07-22 18:46:13 +00:00
};
useEffect(() => {
delayedQuery();
// Cancel previous debounce calls during useEffect cleanup.
return delayedQuery.cancel;
2020-07-23 08:56:03 +00:00
}, [inputValue, delayedQuery]);
2020-07-22 15:16:49 +00:00
2020-07-23 08:56:03 +00:00
// TODO: Maybe merge the two use effects?
2020-07-22 18:46:13 +00:00
useEffect(() => {
if (data && data.queryArtists !== []) {
// Limit artists to 5
const updatedArtists = data.queryArtists.slice(0, 5);
const updatedSuggestions: string[] = updatedArtists.map(
(el: Artist) => {
2020-07-22 18:46:13 +00:00
return el.name;
},
);
setSuggestions(updatedSuggestions);
setArtists(updatedArtists);
2020-07-22 18:46:13 +00:00
}
}, [data]);
2020-07-22 15:16:49 +00:00
return (
<Box
as='section'
direction='row'
justify='center'
margin={{ vertical: 'large' }}
>
<TextInput
2020-07-23 08:56:03 +00:00
value={inputValue}
2020-07-22 18:46:13 +00:00
onChange={handleChange}
2020-07-22 15:16:49 +00:00
placeholder='Type an artist name'
icon={<FormSearch color='plain' />}
dropHeight='large'
suggestions={suggestions}
2020-07-22 15:16:49 +00:00
/>
</Box>
);
};