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
This commit is contained in:
Nuwan 2025-02-13 17:52:14 +05:30
parent 1e623e77de
commit bd2d9410b5
5 changed files with 71 additions and 52 deletions

View File

@ -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 { Row, Col, FormGroup, Input, InputGroup, InputGroupText, ListGroup, ListGroupItem } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useTranslation } from 'react-i18next';
import { autocompleteJamTracks } from '../../helpers/rest';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import useDebouncedValue from '../../hooks/useDebounceValue';
const JKJamTracksAutoComplete = ({ const JKJamTracksAutoComplete = ({
fetchFunc, fetchFunc,
@ -19,14 +18,15 @@ const JKJamTracksAutoComplete = ({
const [songs, setSongs] = useState([]); const [songs, setSongs] = useState([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const inputRef = useRef(null); const inputRef = useRef(null);
const { t } = useTranslation();
const MIN_FILTER_SIZE = 3;
const MIN_FETCH_LIMIT = 5; const MIN_FETCH_LIMIT = 5;
const DELAY = 400;
const fetchAutoCompleteResults = useCallback(() => { const debouncedValue = useDebouncedValue(inputValue, DELAY);
const fetchAutoCompleteResults = () => {
// fetch tracks // fetch tracks
setLoading(true); setLoading(true);
fetchFunc(inputValue, MIN_FETCH_LIMIT) fetchFunc(debouncedValue, MIN_FETCH_LIMIT)
.then(resp => { .then(resp => {
return resp.json(); return resp.json();
}) })
@ -58,15 +58,14 @@ const JKJamTracksAutoComplete = ({
.finally(() => { .finally(() => {
setLoading(false); setLoading(false);
}); });
}, [inputValue]); }
useEffect(() => { useEffect(() => {
if (inputValue && inputValue.length >= MIN_FILTER_SIZE) { console.log('debounced value', debouncedValue)
fetchAutoCompleteResults(); if(debouncedValue && debouncedValue.length > 0){
} else { fetchAutoCompleteResults()
setShowDropdown(false);
} }
}, [inputValue]); }, [debouncedValue]);
const handleInputChange = e => { const handleInputChange = e => {
const val = e.target.value; const val = e.target.value;

View File

@ -82,6 +82,7 @@ const JKJamTracksFilter = () => {
const handleOnSelect = async selected => { const handleOnSelect = async selected => {
page.current = 1; page.current = 1;
setJamTracks([]); setJamTracks([]);
setNextOffset(null)
setSearchTerm(''); setSearchTerm('');
setSelected(selected); setSelected(selected);
const params = queryOptions(selected); const params = queryOptions(selected);
@ -91,6 +92,7 @@ const JKJamTracksFilter = () => {
const handleOnEnter = async queryStr => { const handleOnEnter = async queryStr => {
page.current = 1; page.current = 1;
setJamTracks([]); setJamTracks([]);
setNextOffset(null);
setSelected(x => null); setSelected(x => null);
setSearchTerm(queryStr); setSearchTerm(queryStr);
const params = queryOptions(queryStr); const params = queryOptions(queryStr);

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import useUserProfile from '../hooks/useUserProfile'; import useUserProfile from '../hooks/useUserProfile';
import { useAuth } from './UserAuth'; import { useAuth } from './UserAuth';
//import { useShoppingCart } from '../hooks/useShoppingCart'; import FingerprintJS from '@fingerprintjs/fingerprintjs';
// AppDataContext.js // AppDataContext.js
// this context is used to store app data that is shared across the app // 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 [appData, setAppData] = React.useState({});
const { currentUser } = useAuth(); const { currentUser } = useAuth();
const { userProfile, photoUrl } = useUserProfile({ user: currentUser, useCache: false }); const { userProfile, photoUrl } = useUserProfile({ user: currentUser, useCache: false });
//const { shoppingCart, getCartItems } = useShoppingCart(); const fpPromise = FingerprintJS.load();
// React.useEffect(() => {
// getCartItems();
// }, [currentUser]);
React.useEffect(() => { React.useEffect(() => {
setAppData({ setAppData({
userProfile, currentUserPhotoUrl: userProfile, currentUserPhotoUrl:
photoUrl, photoUrl,
fpPromise
}); });
}, [currentUser, userProfile, photoUrl]); }, [currentUser, userProfile, photoUrl]);

View File

@ -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;

View File

@ -10,7 +10,7 @@ import {
import { SAMPLE_RATE } from '../helpers/jamTracks'; import { SAMPLE_RATE } from '../helpers/jamTracks';
import { createAlert } from '../helpers/rest'; import { createAlert } from '../helpers/rest';
import { useAuth } from '../context/UserAuth'; import { useAuth } from '../context/UserAuth';
import FingerprintJS from '@fingerprintjs/fingerprintjs'; import { useAppData } from '../context/AppDataContext';
export const useJamTrack = () => { export const useJamTrack = () => {
@ -26,7 +26,7 @@ export const useJamTrack = () => {
const watchedMixdowns = useSelector(state => state.jamTrack.watchedMixdowns); const watchedMixdowns = useSelector(state => state.jamTrack.watchedMixdowns);
const { currentUser } = useAuth(); const { currentUser } = useAuth();
const fpPromise = FingerprintJS.load(); const { fpPromise } = useAppData();
const dispatch = useDispatch(); const dispatch = useDispatch();
const [showQueueTime, setShowQueueTime] = useState(false); const [showQueueTime, setShowQueueTime] = useState(false);