From bd2d9410b54209d6deea55f4c061bfedc67e1a1f Mon Sep 17 00:00:00 2001 From: Nuwan Date: Thu, 13 Feb 2025 17:52:14 +0530 Subject: [PATCH] fix jamtrack autocomplete component add debouncing technique to fetch data when fetching the data move the FingerprintJS initialization to the appDataContext so it is not instantiate eveytime --- .../jamtracks/JKJamTracksAutoComplete.js | 87 +++++++++---------- .../components/jamtracks/JKJamTracksFilter.js | 2 + jam-ui/src/context/AppDataContext.js | 9 +- jam-ui/src/hooks/useDebounceValue.js | 21 +++++ jam-ui/src/hooks/useJamTrack.js | 4 +- 5 files changed, 71 insertions(+), 52 deletions(-) create mode 100644 jam-ui/src/hooks/useDebounceValue.js diff --git a/jam-ui/src/components/jamtracks/JKJamTracksAutoComplete.js b/jam-ui/src/components/jamtracks/JKJamTracksAutoComplete.js index 127d6a882..48748238e 100644 --- a/jam-ui/src/components/jamtracks/JKJamTracksAutoComplete.js +++ b/jam-ui/src/components/jamtracks/JKJamTracksAutoComplete.js @@ -1,9 +1,8 @@ -import React, { useEffect, useCallback, useState, useRef } from 'react'; +import React, { useEffect, useState, useRef } from 'react'; import { Row, Col, FormGroup, Input, InputGroup, InputGroupText, ListGroup, ListGroupItem } from 'reactstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { useTranslation } from 'react-i18next'; -import { autocompleteJamTracks } from '../../helpers/rest'; import PropTypes from 'prop-types'; +import useDebouncedValue from '../../hooks/useDebounceValue'; const JKJamTracksAutoComplete = ({ fetchFunc, @@ -19,54 +18,54 @@ const JKJamTracksAutoComplete = ({ const [songs, setSongs] = useState([]); const [loading, setLoading] = useState(false); const inputRef = useRef(null); - const { t } = useTranslation(); - const MIN_FILTER_SIZE = 3; const MIN_FETCH_LIMIT = 5; + const DELAY = 400; - const fetchAutoCompleteResults = useCallback(() => { + const debouncedValue = useDebouncedValue(inputValue, DELAY); + + const fetchAutoCompleteResults = () => { // fetch tracks setLoading(true); - fetchFunc(inputValue, MIN_FETCH_LIMIT) - .then(resp => { - return resp.json(); - }) - .then(data => { - console.log('tracks', data); - if (data.songs) { - const updatedSongs = data.songs.map(song => { - song.type = 'song'; - return song; - }); - setSongs(updatedSongs); - } - if (data.artists) { - const updatedArtists = data.artists.map(artist => { - artist.type = 'artist'; - return artist; - }); - setArtists(updatedArtists); - } - if (data.jamtracks) { - const updatedSongs = data.jamtracks.map(song => { - song.type = 'song'; - return song; - }); - setSongs(updatedSongs); - } - setShowDropdown(true); - }) - .finally(() => { - setLoading(false); - }); - }, [inputValue]); + fetchFunc(debouncedValue, MIN_FETCH_LIMIT) + .then(resp => { + return resp.json(); + }) + .then(data => { + console.log('tracks', data); + if (data.songs) { + const updatedSongs = data.songs.map(song => { + song.type = 'song'; + return song; + }); + setSongs(updatedSongs); + } + if (data.artists) { + const updatedArtists = data.artists.map(artist => { + artist.type = 'artist'; + return artist; + }); + setArtists(updatedArtists); + } + if (data.jamtracks) { + const updatedSongs = data.jamtracks.map(song => { + song.type = 'song'; + return song; + }); + setSongs(updatedSongs); + } + setShowDropdown(true); + }) + .finally(() => { + setLoading(false); + }); + } useEffect(() => { - if (inputValue && inputValue.length >= MIN_FILTER_SIZE) { - fetchAutoCompleteResults(); - } else { - setShowDropdown(false); + console.log('debounced value', debouncedValue) + if(debouncedValue && debouncedValue.length > 0){ + fetchAutoCompleteResults() } - }, [inputValue]); + }, [debouncedValue]); const handleInputChange = e => { const val = e.target.value; diff --git a/jam-ui/src/components/jamtracks/JKJamTracksFilter.js b/jam-ui/src/components/jamtracks/JKJamTracksFilter.js index b50db5b84..436cbd7e7 100644 --- a/jam-ui/src/components/jamtracks/JKJamTracksFilter.js +++ b/jam-ui/src/components/jamtracks/JKJamTracksFilter.js @@ -82,6 +82,7 @@ const JKJamTracksFilter = () => { const handleOnSelect = async selected => { page.current = 1; setJamTracks([]); + setNextOffset(null) setSearchTerm(''); setSelected(selected); const params = queryOptions(selected); @@ -91,6 +92,7 @@ const JKJamTracksFilter = () => { const handleOnEnter = async queryStr => { page.current = 1; setJamTracks([]); + setNextOffset(null); setSelected(x => null); setSearchTerm(queryStr); const params = queryOptions(queryStr); diff --git a/jam-ui/src/context/AppDataContext.js b/jam-ui/src/context/AppDataContext.js index 1ed6f92eb..bb345c2de 100644 --- a/jam-ui/src/context/AppDataContext.js +++ b/jam-ui/src/context/AppDataContext.js @@ -1,7 +1,7 @@ import React from 'react'; import useUserProfile from '../hooks/useUserProfile'; import { useAuth } from './UserAuth'; -//import { useShoppingCart } from '../hooks/useShoppingCart'; +import FingerprintJS from '@fingerprintjs/fingerprintjs'; // AppDataContext.js // this context is used to store app data that is shared across the app @@ -11,16 +11,13 @@ export const AppDataProvider = ({ children }) => { const [appData, setAppData] = React.useState({}); const { currentUser } = useAuth(); const { userProfile, photoUrl } = useUserProfile({ user: currentUser, useCache: false }); - //const { shoppingCart, getCartItems } = useShoppingCart(); - - // React.useEffect(() => { - // getCartItems(); - // }, [currentUser]); + const fpPromise = FingerprintJS.load(); React.useEffect(() => { setAppData({ userProfile, currentUserPhotoUrl: photoUrl, + fpPromise }); }, [currentUser, userProfile, photoUrl]); diff --git a/jam-ui/src/hooks/useDebounceValue.js b/jam-ui/src/hooks/useDebounceValue.js new file mode 100644 index 000000000..a63d0c456 --- /dev/null +++ b/jam-ui/src/hooks/useDebounceValue.js @@ -0,0 +1,21 @@ +import { useEffect, useState } from "react"; +const DEFAULT_DELAY = 500; + +const useDebouncedValue = ( + value = "", + delay = DEFAULT_DELAY +) => { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const timer = setTimeout(() => { + setDebouncedValue(value); + }, delay); + + return () => clearTimeout(timer); + }, [value, delay]); + + return debouncedValue; +}; + +export default useDebouncedValue; diff --git a/jam-ui/src/hooks/useJamTrack.js b/jam-ui/src/hooks/useJamTrack.js index 26552ee4f..3e8b45663 100644 --- a/jam-ui/src/hooks/useJamTrack.js +++ b/jam-ui/src/hooks/useJamTrack.js @@ -10,7 +10,7 @@ import { import { SAMPLE_RATE } from '../helpers/jamTracks'; import { createAlert } from '../helpers/rest'; import { useAuth } from '../context/UserAuth'; -import FingerprintJS from '@fingerprintjs/fingerprintjs'; +import { useAppData } from '../context/AppDataContext'; export const useJamTrack = () => { @@ -26,7 +26,7 @@ export const useJamTrack = () => { const watchedMixdowns = useSelector(state => state.jamTrack.watchedMixdowns); const { currentUser } = useAuth(); - const fpPromise = FingerprintJS.load(); + const { fpPromise } = useAppData(); const dispatch = useDispatch(); const [showQueueTime, setShowQueueTime] = useState(false);