From c92d131ae3d9535fca55b91339a8d08c4dad50ec Mon Sep 17 00:00:00 2001 From: Vyacheslav Matyukhin Date: Fri, 25 Mar 2022 01:23:07 +0300 Subject: [PATCH] feat: reactive search with useEffect --- src/pages/index.tsx | 2 +- src/web/display/commonDisplay.tsx | 125 +++++++++--------- ...yData.js => searchAccordingToQueryData.ts} | 4 +- 3 files changed, 63 insertions(+), 68 deletions(-) rename src/web/worker/{searchAccordingToQueryData.js => searchAccordingToQueryData.ts} (94%) diff --git a/src/pages/index.tsx b/src/pages/index.tsx index e0d96a6..c76129c 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -15,8 +15,8 @@ export const getServerSideProps: GetServerSideProps = async (context) => { let initialQueryParameters = { query: "", + numDisplay: 21, starsThreshold: 2, - numDisplay: 21, // 20 forecastsThreshold: 0, forecastingPlatforms: platformsWithLabels, // weird key value format, ...urlQuery, diff --git a/src/web/display/commonDisplay.tsx b/src/web/display/commonDisplay.tsx index 96de24a..bbf597b 100644 --- a/src/web/display/commonDisplay.tsx +++ b/src/web/display/commonDisplay.tsx @@ -1,4 +1,4 @@ -import React, { Fragment, useState } from 'react'; +import React, { Fragment, useEffect, useState } from 'react'; import { platformNames, PlatformWithLabel } from '../platforms'; import searchAccordingToQueryData from '../worker/searchAccordingToQueryData'; @@ -7,14 +7,17 @@ import Form from './form'; import MultiSelectPlatform from './multiSelectPlatforms'; import { SliderElement } from './slider'; -export interface QueryParameters { +interface QueryParametersWithoutNum { query: string; - numDisplay: number; starsThreshold: number; forecastsThreshold: number; forecastingPlatforms: PlatformWithLabel[]; } +export interface QueryParameters extends QueryParametersWithoutNum { + numDisplay: number; +} + interface Props { initialResults: any; defaultResults: any; @@ -64,17 +67,13 @@ const CommonDisplay: React.FC = ({ }) => { /* States */ - const [queryParameters, setQueryParameters] = useState( - initialQueryParameters - ); - let initialSearchSpeedSettings = { - timeoutId: null, - awaitEndTyping: 500, - time: Date.now(), - }; - const [searchSpeedSettings, setSearchSpeedSettings] = useState( - initialSearchSpeedSettings + const [queryParameters, setQueryParameters] = + useState(initialQueryParameters); + + const [numDisplay, setNumDisplay] = useState( + initialQueryParameters.numDisplay || 21 ); + const [results, setResults] = useState(initialResults); const [advancedOptions, showAdvancedOptions] = useState(false); const [whichResultToDisplayAndCapture, setWhichResultToDisplayAndCapture] = @@ -128,10 +127,9 @@ const CommonDisplay: React.FC = ({ showIdToggle, }) => { let numDisplayRounded = - queryParameters.numDisplay % 3 != 0 - ? queryParameters.numDisplay + - (3 - (Math.round(queryParameters.numDisplay) % 3)) - : queryParameters.numDisplay; + numDisplay % 3 != 0 + ? numDisplay + (3 - (Math.round(numDisplay) % 3)) + : numDisplay; return displayForecastsWrapper({ results, numDisplay: numDisplayRounded, @@ -140,19 +138,20 @@ const CommonDisplay: React.FC = ({ }); }; - /* State controllers */ - let onChangeSearchInputs = (newQueryParameters: QueryParameters) => { - setQueryParameters(newQueryParameters); // ({ ...newQueryParameters, processedUrlYet: true }); + useEffect(() => { setResults([]); - clearTimeout(searchSpeedSettings.timeoutId); - let newtimeoutId = setTimeout(async () => { - let urlSlug = transformObjectIntoUrlSlug(newQueryParameters); + let newTimeoutId = setTimeout(async () => { + let urlSlug = transformObjectIntoUrlSlug({ + ...queryParameters, + numDisplay, + }); let urlWithoutDefaultParameters = urlSlug .replace("?query=&", "?") .replace("&starsThreshold=2", "") .replace("&numDisplay=21", "") .replace("&forecastsThreshold=0", "") .replace(`&forecastingPlatforms=${platformNames.join("|")}`, ""); + console.log(urlWithoutDefaultParameters); if (urlWithoutDefaultParameters != "?query=") { if (typeof window !== "undefined") { if (!window.location.href.includes(urlWithoutDefaultParameters)) { @@ -165,34 +164,40 @@ const CommonDisplay: React.FC = ({ } } - executeSearchOrAnswerWithDefaultResults(newQueryParameters); - setSearchSpeedSettings({ ...searchSpeedSettings, timeoutId: null }); - }, searchSpeedSettings.awaitEndTyping); - setSearchSpeedSettings({ ...searchSpeedSettings, timeoutId: newtimeoutId }); + executeSearchOrAnswerWithDefaultResults({ + ...queryParameters, + numDisplay, + }); + }, 500); + // avoid sending results if user has not stopped typing. - }; + return () => { + clearTimeout(newTimeoutId); + }; + }, [queryParameters]); + + /* State controllers */ /* Change the stars threshold */ let onChangeStars = (value: number) => { - let newQueryParameters: QueryParameters = { + setQueryParameters({ ...queryParameters, starsThreshold: value, - }; - onChangeSearchInputs(newQueryParameters); + }); }; /* Change the number of elements to display */ let displayFunctionNumDisplaySlider = (value) => { - return Math.round(value) != 1 - ? "Show " + Math.round(value) + " results" - : "Show " + Math.round(value) + " result"; + return ( + "Show " + + Math.round(value) + + " result" + + (Math.round(value) === 1 ? "" : "s") + ); }; let onChangeSliderForNumDisplay = (event) => { - let newQueryParameters: QueryParameters = { - ...queryParameters, - numDisplay: Math.round(event[0]), - }; - onChangeSearchInputs(newQueryParameters); // Slightly inefficient because it recomputes the search in time, but it makes my logic easier. + setNumDisplay(Math.round(event[0])); + // FIXME - force new search if numDisplay is greater than last search limit }; /* Change the forecast threshold */ @@ -200,26 +205,26 @@ const CommonDisplay: React.FC = ({ return "# Forecasts > " + Math.round(value); }; let onChangeSliderForNumForecasts = (event) => { - let newQueryParameters = { + setQueryParameters({ ...queryParameters, forecastsThreshold: Math.round(event[0]), - }; - onChangeSearchInputs(newQueryParameters); + }); }; /* Change on the search bar */ let onChangeSearchBar = (value: string) => { - let newQueryParameters = { ...queryParameters, query: value }; - onChangeSearchInputs(newQueryParameters); + setQueryParameters({ + ...queryParameters, + query: value, + }); }; /* Change selected platforms */ let onChangeSelectedPlatforms = (value) => { - let newQueryParameters = { + setQueryParameters({ ...queryParameters, forecastingPlatforms: value, - }; - onChangeSearchInputs(newQueryParameters); + }); }; // Change show id @@ -236,7 +241,6 @@ const CommonDisplay: React.FC = ({ }; let onClickForward = (whichResultToDisplayAndCapture: number) => { setWhichResultToDisplayAndCapture(whichResultToDisplayAndCapture + 1); - // setTimeout(()=> {onClickForward(whichResultToDisplayAndCapture+1)}, 5000) }; /* Final return */ @@ -300,7 +304,7 @@ const CommonDisplay: React.FC = ({
@@ -329,31 +333,22 @@ const CommonDisplay: React.FC = ({ })}
- {displaySeeMoreHint ? ( + {displaySeeMoreHint && + (!results || (results.length != 0 && numDisplay < results.length)) ? (
-

+

{"Can't find what you were looking for?"} { - setQueryParameters({ - ...queryParameters, - numDisplay: queryParameters.numDisplay * 2, - }); + setNumDisplay(numDisplay * 2); }} > - {" Show more, or"} - {" "} + {" Show more,"} + + {" or "}