Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion apps/mobile/src/app/(tabs)/fertilizers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { SwipeToDelete } from '../../components/SwipeToDelete'

import { useAlert } from '../../contexts/AlertContext'

import { useDebounce } from '../../hooks/useDebounce'
import { useRefreshOnFocus } from '../../hooks/useRefetchOnFocus'

import { trpc } from '../../trpc'
Expand All @@ -36,6 +37,7 @@ export function FertilizersScreen() {
const [expandedIds, setExpandedIds] = React.useState<Set<string>>(new Set())
const [filterModalVisible, setFilterModalVisible] = React.useState(false)
const [searchQuery, setSearchQuery] = React.useState('')
const debouncedSearchQuery = useDebounce(searchQuery.trim(), 300)

useLayoutEffect(() => {
navigation.setOptions({
Expand Down Expand Up @@ -79,7 +81,7 @@ export function FertilizersScreen() {
isRefetching,
refetch,
} = trpc.fertilizers.list.useQuery({
q: searchQuery || undefined,
q: debouncedSearchQuery || undefined,
sortBy: [
{ field: 'name', direction: 'asc' },
],
Expand Down
4 changes: 3 additions & 1 deletion apps/mobile/src/app/(tabs)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { SnoozeChoreModal } from '../../components/SnoozeChoreModal'

import { useAlert } from '../../contexts/AlertContext'

import { useDebounce } from '../../hooks/useDebounce'
import { useRefreshOnFocus } from '../../hooks/useRefetchOnFocus'

import { trpc } from '../../trpc'
Expand All @@ -34,6 +35,7 @@ function ToDoScreen() {
const [snoozeChore, setSnoozeChore] = useState<NonNullable<typeof data>['chores'][0] | null>(null)
const [filterModalVisible, setFilterModalVisible] = useState(false)
const [searchQuery, setSearchQuery] = useState('')
const debouncedSearchQuery = useDebounce(searchQuery.trim(), 300)

useLayoutEffect(() => {
navigation.setOptions({
Expand All @@ -60,7 +62,7 @@ function ToDoScreen() {
} = trpc.chores.list.useQuery({
includeDoneItems: true, // load all items from API, filter out done items in the client
includeNotYetDueItems: true, // load all items from API, filter out future items in the client
q: searchQuery || undefined,
q: debouncedSearchQuery || undefined,
sortBy: [
{ field: 'nextDate', direction: 'asc' },
{ field: 'plant', direction: 'asc' },
Expand Down
4 changes: 3 additions & 1 deletion apps/mobile/src/app/(tabs)/plants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { SwipeToDelete } from '../../components/SwipeToDelete'

import { useAlert } from '../../contexts/AlertContext'

import { useDebounce } from '../../hooks/useDebounce'
import { useRefreshOnFocus } from '../../hooks/useRefetchOnFocus'

import { trpc, type Endpoints } from '../../trpc'
Expand Down Expand Up @@ -106,6 +107,7 @@ export function PlantsScreen() {
const [editingPlantSpecies, setEditingPlantSpecies] = React.useState<ISpecies | null>(null)
const [filterModalVisible, setFilterModalVisible] = React.useState(false)
const [searchQuery, setSearchQuery] = React.useState('')
const debouncedSearchQuery = useDebounce(searchQuery.trim(), 300)

useLayoutEffect(() => {
navigation.setOptions({
Expand All @@ -130,7 +132,7 @@ export function PlantsScreen() {
isRefetching,
refetch,
} = trpc.plants.list.useQuery({
q: searchQuery || undefined,
q: debouncedSearchQuery || undefined,
sortBy: [
{ field: 'name', direction: 'asc' },
],
Expand Down
27 changes: 27 additions & 0 deletions apps/mobile/src/hooks/useDebounce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useEffect, useState } from 'react'

/**
* Debounce any changing value.
*
* Example:
* const debouncedSearch = useDebounce(search, 300)
*/
export function useDebounce<T>(value: T, delayMs = 300) {
const [debouncedValue, setDebouncedValue] = useState<T>(value)

useEffect(() => {
// No delay: update immediately
if (delayMs <= 0) {
setDebouncedValue(value)
return
}

const timeout = setTimeout(() => {
setDebouncedValue(value)
}, delayMs)

return () => clearTimeout(timeout)
}, [delayMs, value])

return debouncedValue
}