From ce1bd7de403f43068f5d685fc65a4dc010ac88d3 Mon Sep 17 00:00:00 2001 From: rui hildt Date: Thu, 23 Jul 2020 11:43:12 +0200 Subject: [PATCH] Move state to App component --- src/components/App.tsx | 93 ++++++++++++++++++++++++++++++------ src/components/Results.tsx | 14 ++++++ src/components/Search.tsx | 29 +++++++++++ src/components/SearchBox.tsx | 82 ------------------------------- 4 files changed, 121 insertions(+), 97 deletions(-) create mode 100644 src/components/Results.tsx create mode 100644 src/components/Search.tsx delete mode 100644 src/components/SearchBox.tsx diff --git a/src/components/App.tsx b/src/components/App.tsx index 0fd7ff2..9b0ca38 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1,7 +1,83 @@ -import React from 'react'; +import React, { useState, useCallback, useEffect } from 'react'; import { Grommet } from 'grommet'; +import { debounce } from 'lodash'; +import { gql, useLazyQuery } from '@apollo/client'; + import { Header } from './Header'; -import { SearchBox } from './SearchBox'; +import { Search } from './Search'; +import { Results } from './Results'; +import { Artists, Artist } from '../interfaces'; + +const QUERY_ARTIST_ALBUMS = gql` + query Artist($byName: String!) { + queryArtists(byName: $byName) { + name + image + id + albums { + name + image + id + } + } + } +`; + +export default function App() { + const [inputValue, setInputValue] = useState(''); + const [getArtists, { data }] = useLazyQuery(QUERY_ARTIST_ALBUMS); + const [artists, setArtists] = useState(undefined); + const [suggestions, setSuggestions] = useState( + undefined, + ); + + // Debounce the database query + // See: https://archive.is/wip/6JDqb + const updateQuery = () => { + getArtists({ variables: { byName: inputValue } }); + }; + + const delayedQuery = useCallback(debounce(updateQuery, 500), [inputValue]); + + const handleChange = (e: React.ChangeEvent) => { + setInputValue(e.target.value); + }; + + useEffect(() => { + delayedQuery(); + // Cancel previous debounce calls during useEffect cleanup. + return delayedQuery.cancel; + }, [inputValue, delayedQuery]); + + // TODO: Maybe merge the two use effects? + useEffect(() => { + if (data && data.queryArtists !== []) { + // Limit artists to 5 + const updatedArtists = data.queryArtists.slice(0, 5); + const updatedSuggestions: string[] = updatedArtists.map( + (el: Artist) => { + return el.name; + }, + ); + setSuggestions(updatedSuggestions); + setArtists(updatedArtists); + } + }, [data]); + + return ( + +
+

Spoti Search

+
+ + +
+ ); +} const theme = { global: { @@ -12,16 +88,3 @@ const theme = { }, }, }; - -function App() { - return ( - -
-

Spoti Search

-
- -
- ); -} - -export default App; diff --git a/src/components/Results.tsx b/src/components/Results.tsx new file mode 100644 index 0000000..909d5db --- /dev/null +++ b/src/components/Results.tsx @@ -0,0 +1,14 @@ +import React, { PropsWithChildren } from 'react'; +import { Box } from 'grommet'; + +export const Results = (props: PropsWithChildren<{}>) => { + return ( + + + ); +}; diff --git a/src/components/Search.tsx b/src/components/Search.tsx new file mode 100644 index 0000000..82e8b4e --- /dev/null +++ b/src/components/Search.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Box, TextInput } from 'grommet'; +import { FormSearch } from 'grommet-icons'; + +export const Search = ({ + inputValue, + handleChange, + suggestions, +}: { + inputValue: string; + handleChange: (e: React.ChangeEvent) => void; + suggestions: string[] | undefined; +}) => ( + + } + dropHeight='large' + suggestions={suggestions} + /> + +); diff --git a/src/components/SearchBox.tsx b/src/components/SearchBox.tsx deleted file mode 100644 index 30d28b8..0000000 --- a/src/components/SearchBox.tsx +++ /dev/null @@ -1,82 +0,0 @@ -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'; - -import { Artists, Artist } from '../interfaces'; - -const QUERY_ARTIST_ALBUMS = gql` - query Artist($byName: String!) { - queryArtists(byName: $byName) { - name - image - id - albums { - name - image - id - } - } - } -`; - -export const SearchBox = () => { - const [inputValue, setInputValue] = useState(''); - const [getArtists, { data }] = useLazyQuery(QUERY_ARTIST_ALBUMS); - const [artists, setArtists] = useState(undefined); - const [suggestions, setSuggestions] = useState( - undefined, - ); - - // 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 = () => { - getArtists({ variables: { byName: inputValue } }); - }; - - const delayedQuery = useCallback(debounce(updateQuery, 500), [inputValue]); - - const handleChange = (e: any) => { - setInputValue(e.target.value); - }; - - useEffect(() => { - delayedQuery(); - // Cancel previous debounce calls during useEffect cleanup. - return delayedQuery.cancel; - }, [inputValue, delayedQuery]); - - // TODO: Maybe merge the two use effects? - useEffect(() => { - if (data && data.queryArtists !== []) { - // Limit artists to 5 - const updatedArtists = data.queryArtists.slice(0, 5); - const updatedSuggestions: string[] = updatedArtists.map( - (el: Artist) => { - return el.name; - }, - ); - setSuggestions(updatedSuggestions); - setArtists(updatedArtists); - } - }, [data]); - - return ( - - } - dropHeight='large' - suggestions={suggestions} - /> - - ); -};