Skip to content

Conversation

@YoussefHenna
Copy link
Collaborator

  • The title basically
  • Will allow users to make API calls on text change after a delay when typing stops. Prevents overloading API with requests on every character.

@YoussefHenna YoussefHenna added the legacy For a legacy branch using an older Expo version label Jun 5, 2023
@linear
Copy link

linear bot commented Jun 5, 2023

P-3664 Debounced Value

Its essential thing for common search bar UX. I had to implemented this in 3 experts project till now. The way I envision is we can start with input field. Like we have a access to data source variable in the action panel. We should a debounced version of that variable. That can be accessable in the action.

image.png

The way I implement is that I have a custom hook for debounced value:

//hooks.js
// This import is required if you are defining react components in this module.
import { useEffect, useState } from 'react';

export const useDebounce = (value, delay) => {
  const [deboncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const hanlder = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => {
      clearTimeout(hanlder);
    };
  }, [value, delay]);

  return deboncedValue;
};

I want a api call to be triggered each time the debounced variable is changed. I couldn't thought of a better way other than this.

// This import is required if you are defining react components in this module.
import React, { useMemo, useEffect } from 'react';
import * as PublicAuthRequiredApi from '../apis/PublicAuthRequiredApi.js';
import * as GlobalVariables from '../config/GlobalVariableContext';
import * as GlobalStyles from '../GlobalStyles.js';

// Add any other imports you need here. Make sure to add those imports (besides "react"
// and "react-native") to the Packages section.
import { TextInput, StyleSheet } from 'react-native';
import { useDebounce } from './hooks';
// Define and export your components as named exports here.

// You can use components exported from this file within a Custom Code component as
// <D.MyExampleComponent />
export const PlayerSearch = ({
  query,
  setQuery,
  setIsQuerying,
  theme
}) => {
  const Constants = GlobalVariables.useValues();
  const setGlobalVariableValue = GlobalVariables.useSetValue();

  const debouncedQuery = useDebounce(query, 500);

  useEffect(() => {
    const handler = async () => {
      // console.log('handler called', debouncedQuery);
      try {
        setIsQuerying(true);
        const players = await PublicAuthRequiredApi.searchPlayersPOST(
          Constants,
          {
            query: debouncedQuery,
          }
        );
        // console.log(players);
        setGlobalVariableValue({
          key: 'SEARCHABLE_PLAYERS',
          value: players,
        });
        setIsQuerying(false);
      } catch (err) {
        console.error(err);
      }
    };
    handler();
  }, [debouncedQuery]);

  return (
    <TextInput
      onChangeText={newVal => setQuery(newVal)}
      style={[
        GlobalStyles.TextInputStyles(theme)['Input Source Sans Pro'],
        styles(theme).TextInput72ad7d1d,
      ]}
      value={query}
      // disabled={addingNew}
      placeholder={'Search player'}
      autoCapitalize={'none'}
      placeholderTextColor={theme.colors['Neutral/200 - Gray']}
      clearButtonMode={'while-editing'}
      keyboardType={'default'}
      autoFocus={true}
    />
  );
};

export const CourtSearch = ({ query, setQuery, setIsQuerying, theme }) => {
  const Constants = GlobalVariables.useValues();
  const setGlobalVariableValue = GlobalVariables.useSetValue();

  const debouncedQuery = useDebounce(query, 500);

  useEffect(() => {
    const handler = async () => {
      // console.log('handler called', debouncedQuery);
      try {
        setIsQuerying(true);
        const venues = await PublicAuthRequiredApi.searchVenuePOST(Constants, {
          query: debouncedQuery,
        });
        // console.log(venues);
        setGlobalVariableValue({
          key: 'SEARCHABLE_COURTS',
          value: venues,
        });
        setIsQuerying(false);
      } catch (err) {
        console.error(err);
      }
    };
    handler();
  }, [debouncedQuery]);

  return (
    <TextInput
      onChangeText={newVal => setQuery(newVal)}
      style={[
        GlobalStyles.TextInputStyles(theme)['Input Source Sans Pro'],
        styles(theme).TextInput72ad7d1d,
      ]}
      value={query}
      // disabled={addingNew}
      placeholder={'Search courts'}
      autoCapitalize={'none'}
      placeholderTextColor={theme.colors['Neutral/200 - Gray']}
      clearButtonMode={'while-editing'}
      keyboardType={'default'}
      autoFocus={true}
    />
  );
};

export const CourtSearchWithCords = ({
  query,
  setQuery,
  setIsQuerying,
  theme,
  setVenues,
  lat,
  long,
  showVenues,
  setShowVenues
}) => {
  const Constants = GlobalVariables.useValues();

  const debouncedQuery = useDebounce(query, 500);

  useEffect(() => {
    const handler = async () => {
      // console.log('handler called', debouncedQuery);
      try {
        setIsQuerying(true);
        const venues = await PublicAuthRequiredApi.searchVenuesWithCordsPOST(
          Constants,
          {
            lat,
            long,
            query: debouncedQuery,
          }
        );
        // console.log(venues);
        // setGlobalVariableValue({
        //   key: 'SEARCHABLE_COURTS',
        //   value: venues,
        // });
        setVenues(venues);
        setIsQuerying(false);
      } catch (err) {
        console.error(err);
      }
    };
    if (showVenues) handler();
  }, [debouncedQuery, showVenues]);

  return (
    <TextInput
      onChangeText={newVal => setQuery(newVal)}
      style={[
        GlobalStyles.TextInputStyles(theme)['Input Source Sans Pro'],
        styles(theme).TextInput72ad7d1d,
      ]}
      value={query}
      onFocus={() => setShowVenues(true)}
      // onBlur={()=> setShowVenues(false)}
      // disabled={addingNew}
      placeholder={'Search courts'}
      autoCapitalize={'none'}
      placeholderTextColor={theme.colors['Neutral/200 - Gray']}
      clearButtonMode={'while-editing'}
      keyboardType={'default'}
      // autoFocus={true}
    />
  );
};

const styles = theme =>
  StyleSheet.create({
    TextInput72ad7d1d: {
      borderBottomWidth: 0,
      borderLeftWidth: 0,
      borderRadius: 0,
      borderRightWidth: 0,
      borderTopWidth: 0,
      color: theme.colors['Neutral/200 - Gray'],
      fontFamily: 'SourceSansPro_400Regular',
      paddingBottom: 8,
      paddingLeft: 8,
      paddingRight: 8,
      paddingTop: 8,
    },
  });

We should have a property in property panel to control the property panel and a switch to decide if user wants a debounced value or not. Let me know If that could be done in a better way. I can improve my implementation.

Thanks

@YoussefHenna YoussefHenna changed the base branch from master to 47 June 5, 2023 12:43
@YoussefHenna YoussefHenna merged commit c3e99ea into 47 Jun 6, 2023
@YoussefHenna YoussefHenna deleted the youssef/p-3664-debounced-value47 branch June 6, 2023 08:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

legacy For a legacy branch using an older Expo version

Development

Successfully merging this pull request may close these issues.

2 participants