From 07f1a6c2ea5ad5b1cded9b3493c8fbded00d5a44 Mon Sep 17 00:00:00 2001 From: rui hildt Date: Wed, 22 Jul 2020 20:46:13 +0200 Subject: [PATCH] Implement debounced search query --- package.json | 2 ++ src/components/SearchBox.tsx | 60 ++++++++++++++++++++++++++++-------- yarn.lock | 5 +++ 3 files changed, 54 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 79ccb60..1531ff4 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,14 @@ "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", "@types/jest": "^24.0.0", + "@types/lodash": "^4.14.158", "@types/node": "^12.0.0", "@types/react": "^16.9.0", "@types/react-dom": "^16.9.0", "graphql": "^15.3.0", "grommet": "^2.14.0", "grommet-icons": "^4.4.0", + "lodash": "^4.17.19", "react": "^16.13.1", "react-dom": "^16.13.1", "react-scripts": "3.4.1", diff --git a/src/components/SearchBox.tsx b/src/components/SearchBox.tsx index da230c3..a5c9112 100644 --- a/src/components/SearchBox.tsx +++ b/src/components/SearchBox.tsx @@ -1,17 +1,54 @@ -import React, { useState } from 'react'; +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 - let suggestions = [ - 'The Doors', - 'The Doors With Eddie Vedder', - 'The Doorstep Carolers', - 'The Doors Experience', - 'Darken the Doorstep', - ]; + // 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 ( { > setValue(event.target.value)} + onChange={handleChange} placeholder='Type an artist name' icon={} - dropProps={{ - overflow: 'visible', - }} dropHeight='large' - suggestions={suggestions} + suggestions= {suggestions} /> ); diff --git a/yarn.lock b/yarn.lock index 0160d40..476ca0b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1607,6 +1607,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== +"@types/lodash@^4.14.158": + version "4.14.158" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.158.tgz#b38ea8b6fe799acd076d7a8d7ab71c26ef77f785" + integrity sha512-InCEXJNTv/59yO4VSfuvNrZHt7eeNtWQEgnieIA+mIC+MOWM9arOWG2eQ8Vhk6NbOre6/BidiXhkZYeDY9U35w== + "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"