a very good jj gui
1# Rule: Discourage useEffect for state synchronization
2# State derived from other state should use derived atoms, selectors, or reducers
3# instead of useEffect + setState patterns
4
5id: no-useeffect-state-sync
6language: tsx
7severity: warning
8message: "useEffect that calls setState is often an anti-pattern. Consider derived state, useMemo, TanStack Query, or event callbacks instead."
9note: |
10 Common anti-patterns this catches:
11
12 1. Syncing derived state:
13 useEffect(() => { setDerived(compute(source)) }, [source])
14 → Use useMemo or derived atoms
15
16 2. Data fetching:
17 useEffect(() => { fetch().then(setData) }, [])
18 → Use TanStack Query or TanStack DB
19
20 3. Resetting state on prop change:
21 useEffect(() => { setState(initial) }, [id])
22 → Use key prop: <Component key={id} />
23
24 Legitimate useEffect + setState (suppress with biome-ignore):
25 - DOM event subscriptions (resize, keydown, etc.)
26 - External library callbacks
27 - Imperative animations
28
29rule:
30 kind: call_expression
31 all:
32 - has:
33 kind: identifier
34 regex: "^useEffect$"
35 - has:
36 kind: arguments
37 has:
38 kind: arrow_function
39 has:
40 stopBy: end
41 kind: call_expression
42 has:
43 kind: identifier
44 regex: "^set[A-Z]"