fix(CQ-WEB-2): Fix missing dependency in FilterBar useEffect
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
The debounced search useEffect accessed `filters` and `onFilterChange` without including them in the dependency array. Fixed by: - Using useRef for onFilterChange to maintain a stable reference - Using functional state update (setFilters callback) to access previous filters without needing it as a dependency This prevents stale closures while avoiding infinite re-render loops that would occur if these values were added directly to the dep array. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect, useCallback } from "react";
|
import { useState, useEffect, useCallback, useRef } from "react";
|
||||||
import { TaskStatus, TaskPriority } from "@mosaic/shared";
|
import { TaskStatus, TaskPriority } from "@mosaic/shared";
|
||||||
|
|
||||||
export interface FilterValues {
|
export interface FilterValues {
|
||||||
@@ -29,19 +29,28 @@ export function FilterBar({
|
|||||||
const [showStatusDropdown, setShowStatusDropdown] = useState(false);
|
const [showStatusDropdown, setShowStatusDropdown] = useState(false);
|
||||||
const [showPriorityDropdown, setShowPriorityDropdown] = useState(false);
|
const [showPriorityDropdown, setShowPriorityDropdown] = useState(false);
|
||||||
|
|
||||||
|
// Stable ref for onFilterChange to avoid re-triggering the debounce effect
|
||||||
|
const onFilterChangeRef = useRef(onFilterChange);
|
||||||
|
useEffect(() => {
|
||||||
|
onFilterChangeRef.current = onFilterChange;
|
||||||
|
}, [onFilterChange]);
|
||||||
|
|
||||||
// Debounced search
|
// Debounced search
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
if (searchValue !== filters.search) {
|
setFilters((prevFilters) => {
|
||||||
const newFilters = { ...filters };
|
if (searchValue !== prevFilters.search) {
|
||||||
if (searchValue) {
|
const newFilters = { ...prevFilters };
|
||||||
newFilters.search = searchValue;
|
if (searchValue) {
|
||||||
} else {
|
newFilters.search = searchValue;
|
||||||
delete newFilters.search;
|
} else {
|
||||||
|
delete newFilters.search;
|
||||||
|
}
|
||||||
|
onFilterChangeRef.current(newFilters);
|
||||||
|
return newFilters;
|
||||||
}
|
}
|
||||||
setFilters(newFilters);
|
return prevFilters;
|
||||||
onFilterChange(newFilters);
|
});
|
||||||
}
|
|
||||||
}, debounceMs);
|
}, debounceMs);
|
||||||
|
|
||||||
return (): void => {
|
return (): void => {
|
||||||
|
|||||||
@@ -38,6 +38,12 @@ The orchestrator **cold-starts** with just a review report location and minimal
|
|||||||
**If you find yourself about to edit source code, STOP.**
|
**If you find yourself about to edit source code, STOP.**
|
||||||
Spawn a worker instead. No exceptions. No "quick fixes."
|
Spawn a worker instead. No exceptions. No "quick fixes."
|
||||||
|
|
||||||
|
**Worker Limits:**
|
||||||
|
|
||||||
|
- Maximum **2 parallel workers** at any time
|
||||||
|
- Wait for at least one worker to complete before spawning more
|
||||||
|
- This optimizes token usage and reduces context pressure
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Bootstrap Templates
|
## Bootstrap Templates
|
||||||
|
|||||||
Reference in New Issue
Block a user