Skip to content

Commit cfceb53

Browse files
committed
feat: fix use effect usage
1 parent 9456d04 commit cfceb53

5 files changed

Lines changed: 55 additions & 78 deletions

File tree

apps/web/src/components/dashboard-builder/config/query-panel.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,11 @@ function GroupByMultiSelect({
126126

127127
const isOpen = isFocused && !isDismissed && suggestions.length > 0
128128

129-
React.useEffect(() => {
129+
const handleInputChange = React.useCallback((nextValue: string) => {
130+
setInputValue(nextValue)
130131
setActiveIndex(0)
131-
}, [suggestions.length, inputValue])
132+
setIsDismissed(false)
133+
}, [])
132134

133135
const addKey = React.useCallback(
134136
(key: string) => {
@@ -194,10 +196,7 @@ function GroupByMultiSelect({
194196
setIsDismissed(false)
195197
}}
196198
onBlur={() => setIsFocused(false)}
197-
onChange={(event) => {
198-
setInputValue(event.target.value)
199-
setIsDismissed(false)
200-
}}
199+
onChange={(event) => handleInputChange(event.target.value)}
201200
onKeyDown={(event) => {
202201
if (event.key === "Backspace" && !inputValue && value.length > 0) {
203202
removeKey(value[value.length - 1])

apps/web/src/components/dashboard-builder/config/widget-query-builder-page.tsx

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -555,31 +555,35 @@ export function WidgetQueryBuilderPage({
555555
}
556556
}, [logsFacetsResult, metricRows, tracesFacetsResult, attributeKeys, attributeValues, resourceAttributeKeys, resourceAttributeValues])
557557

558-
React.useEffect(() => {
559-
if (metricSelectionOptions.length === 0) return
560-
setState((current) => {
561-
const [defaultMetricName, defaultMetricTypeRaw] = metricSelectionOptions[0].value.split("::")
562-
const defaultMetricType = defaultMetricTypeRaw as QueryBuilderMetricType
563-
let changed = false
564-
const queries = current.queries.map((query) => {
565-
if (query.dataSource !== "metrics" || query.metricName || !defaultMetricName || !defaultMetricType) return query
566-
changed = true
567-
return { ...query, metricName: defaultMetricName, metricType: defaultMetricType }
558+
const appliedMetricDefaultRef = React.useRef(false)
559+
if (metricSelectionOptions.length > 0 && !appliedMetricDefaultRef.current) {
560+
const [defaultMetricName, defaultMetricTypeRaw] = metricSelectionOptions[0].value.split("::")
561+
const defaultMetricType = defaultMetricTypeRaw as QueryBuilderMetricType
562+
const needsDefault = state.queries.some(
563+
(query) => query.dataSource === "metrics" && !query.metricName && defaultMetricName && defaultMetricType,
564+
)
565+
if (needsDefault) {
566+
appliedMetricDefaultRef.current = true
567+
setState((current) => {
568+
let changed = false
569+
const queries = current.queries.map((query) => {
570+
if (query.dataSource !== "metrics" || query.metricName || !defaultMetricName || !defaultMetricType) return query
571+
changed = true
572+
return { ...query, metricName: defaultMetricName, metricType: defaultMetricType }
573+
})
574+
return changed ? { ...current, queries } : current
568575
})
569-
return changed ? { ...current, queries } : current
570-
})
571-
}, [metricSelectionOptions])
576+
}
577+
}
572578

573579
const seriesFieldOptions = React.useMemo(() => toSeriesFieldOptions(state), [state])
574580

575-
React.useEffect(() => {
576-
if (state.visualization !== "stat" || seriesFieldOptions.length === 0) return
577-
if (state.statValueField && seriesFieldOptions.includes(state.statValueField)) return
578-
setState((current) => {
579-
if (current.statValueField && seriesFieldOptions.includes(current.statValueField)) return current
580-
return { ...current, statValueField: seriesFieldOptions[0] }
581-
})
582-
}, [widget, state, seriesFieldOptions])
581+
const effectiveStatValueField =
582+
state.visualization === "stat" &&
583+
seriesFieldOptions.length > 0 &&
584+
(!state.statValueField || !seriesFieldOptions.includes(state.statValueField))
585+
? seriesFieldOptions[0]
586+
: state.statValueField
583587

584588
const previewWidget = React.useMemo(() => {
585589
const previewState = stagedState ?? state
@@ -754,7 +758,7 @@ export function WidgetQueryBuilderPage({
754758
includePercentChange={state.includePercentChange}
755759
debug={state.debug}
756760
statAggregate={state.statAggregate}
757-
statValueField={state.statValueField}
761+
statValueField={effectiveStatValueField}
758762
unit={state.unit}
759763
tableLimit={state.tableLimit}
760764
seriesFieldOptions={seriesFieldOptions}

apps/web/src/components/dashboard-builder/inline-editable-title.tsx

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useRef, useEffect } from "react"
1+
import { useState, useRef, useCallback } from "react"
22

33
export function InlineEditableTitle({
44
value,
@@ -13,22 +13,17 @@ export function InlineEditableTitle({
1313
const [draft, setDraft] = useState(value)
1414
const inputRef = useRef<HTMLInputElement>(null)
1515

16-
useEffect(() => {
16+
const startEditing = useCallback(() => {
17+
if (readOnly) return
1718
setDraft(value)
18-
}, [value])
19-
20-
useEffect(() => {
21-
if (isEditing) {
22-
inputRef.current?.select()
23-
}
24-
}, [isEditing])
19+
setIsEditing(true)
20+
requestAnimationFrame(() => inputRef.current?.select())
21+
}, [readOnly, value])
2522

2623
const handleSubmit = () => {
2724
const trimmed = draft.trim()
2825
if (trimmed && trimmed !== value) {
2926
onChange(trimmed)
30-
} else {
31-
setDraft(value)
3227
}
3328
setIsEditing(false)
3429
}
@@ -62,15 +57,11 @@ export function InlineEditableTitle({
6257
<h1
6358
role="button"
6459
tabIndex={0}
65-
onClick={() => {
66-
if (readOnly) return
67-
setIsEditing(true)
68-
}}
60+
onClick={startEditing}
6961
onKeyDown={(e) => {
70-
if (readOnly) return
7162
if (e.key === "Enter" || e.key === " ") {
7263
e.preventDefault()
73-
setIsEditing(true)
64+
startEditing()
7465
}
7566
}}
7667
aria-disabled={readOnly}

apps/web/src/components/logs/logs-filter-sidebar.tsx

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Result, useAtomValue } from "@/lib/effect-atom"
2-
import { useEffect, useState } from "react"
2+
import { useCallback, useRef, useState } from "react"
33
import { useNavigate } from "@tanstack/react-router"
44
import { XmarkIcon, MagnifierIcon } from "@/components/icons"
55

@@ -31,22 +31,21 @@ export function LogsFilterSidebar() {
3131
useEffectiveTimeRange(search.startTime, search.endTime, search.timePreset ?? "12h")
3232

3333
const [searchText, setSearchText] = useState(search.search ?? "")
34+
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
3435

35-
useEffect(() => {
36-
setSearchText(search.search ?? "")
37-
}, [search.search])
38-
39-
useEffect(() => {
40-
const timer = setTimeout(() => {
41-
const value = searchText.trim() || undefined
42-
if (value !== search.search) {
36+
const handleSearchChange = useCallback(
37+
(value: string) => {
38+
setSearchText(value)
39+
if (debounceRef.current) clearTimeout(debounceRef.current)
40+
debounceRef.current = setTimeout(() => {
41+
const trimmed = value.trim() || undefined
4342
navigate({
44-
search: (prev) => ({ ...prev, search: value }),
43+
search: (prev) => ({ ...prev, search: trimmed }),
4544
})
46-
}
47-
}, 300)
48-
return () => clearTimeout(timer)
49-
}, [searchText, search.search, navigate])
45+
}, 300)
46+
},
47+
[navigate],
48+
)
5049

5150
const facetsResult = useAtomValue(
5251
getLogsFacetsResultAtom({
@@ -111,14 +110,14 @@ export function LogsFilterSidebar() {
111110
<input
112111
type="text"
113112
value={searchText}
114-
onChange={(e) => setSearchText(e.target.value)}
113+
onChange={(e) => handleSearchChange(e.target.value)}
115114
placeholder="Search log messages..."
116115
className="h-7 w-full rounded-md border border-input bg-background pl-7 pr-7 text-xs placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
117116
/>
118117
{searchText && (
119118
<button
120119
type="button"
121-
onClick={() => setSearchText("")}
120+
onClick={() => handleSearchChange("")}
122121
className="absolute right-1.5 top-1/2 -translate-y-1/2 rounded-sm p-0.5 text-muted-foreground hover:text-foreground"
123122
>
124123
<XmarkIcon strokeWidth={2} className="size-3" />

apps/web/src/components/time-range-picker/custom-range-picker.tsx

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useEffect } from "react"
1+
import { useState } from "react"
22
import { Calendar } from "@maple/ui/components/ui/calendar"
33
import { Button } from "@maple/ui/components/ui/button"
44
import { Input } from "@maple/ui/components/ui/input"
@@ -33,22 +33,6 @@ export function CustomRangePicker({
3333
return endTime ? format(new Date(endTime), "HH:mm") : "23:59"
3434
})
3535

36-
useEffect(() => {
37-
const from = startTime ? new Date(startTime) : undefined
38-
const to = endTime ? new Date(endTime) : undefined
39-
40-
if (from) {
41-
setStartTimeInput(format(from, "HH:mm"))
42-
}
43-
if (to) {
44-
setEndTimeInput(format(to, "HH:mm"))
45-
}
46-
47-
if (from || to) {
48-
setDateRange({ from, to })
49-
}
50-
}, [startTime, endTime])
51-
5236
const handleApply = () => {
5337
if (!dateRange?.from || !dateRange?.to) return
5438

0 commit comments

Comments
 (0)