mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
* chore(ai-workflow): track repo-managed review tooling * fix(ai-workflow): remove repo-specific path assumptions Make shared workflow hooks and APK testing guidance resolve paths from the repo and contributor environment so the tooling works for all contributors, not just one machine.
4.4 KiB
4.4 KiB
name, description, disable-model-invocation
| name | description | disable-model-invocation |
|---|---|---|
| you-might-not-need-an-effect | Analyze code for useEffect anti-patterns and refactor to simpler alternatives. Use when the user says "you might not need an effect", "check effects", "useEffect audit", or asks to review useEffect usage. | true |
You Might Not Need an Effect
Analyze code for useEffect anti-patterns and refactor to simpler, more correct alternatives.
Based on https://react.dev/learn/you-might-not-need-an-effect
Arguments
- scope: what to analyze (default: uncommitted changes). Examples:
diff to main,src/components/,whole codebase - fix: whether to apply fixes (default:
true). Set tofalseto only propose changes.
Workflow
-
Determine scope — get the relevant code:
- Default:
git difffor uncommitted changes - If a directory/file is specified, read those files
- If "whole codebase": search all
.tsx/.tsfiles foruseEffect
- Default:
-
Scan for anti-patterns — check each
useEffectagainst the patterns below -
Fix or propose — depending on the
fixargument:fix=true: apply the refactors, then verify withyarn build && yarn lint && yarn type-checkfix=false: list each anti-pattern found with a before/after code suggestion
-
Report — summarize what was found and changed
Anti-Patterns to Catch
1. Deriving state during render (no effect needed)
If you're computing something from existing props or state, calculate it during render.
// ❌ Anti-pattern
const [fullName, setFullName] = useState('');
useEffect(() => {
setFullName(firstName + ' ' + lastName);
}, [firstName, lastName]);
// ✅ Fix — derive during render
const fullName = firstName + ' ' + lastName;
2. Caching expensive calculations (useMemo, not useEffect)
// ❌ Anti-pattern
const [filtered, setFiltered] = useState([]);
useEffect(() => {
setFiltered(items.filter(item => item.active));
}, [items]);
// ✅ Fix — calculate during render (useMemo only if profiling shows it's needed)
const filtered = items.filter(item => item.active);
3. Resetting state when props change (use key, not useEffect)
// ❌ Anti-pattern
useEffect(() => {
setComment('');
}, [postCid]);
// ✅ Fix — use key on the component to reset state
<CommentForm key={postCid} />
4. Fetching data (use bitsocial-react-hooks, not useEffect)
This project uses bitsocial-react-hooks for all data fetching. Never use useEffect + fetch.
// ❌ Anti-pattern
const [comment, setComment] = useState(null);
useEffect(() => {
fetchComment(cid).then(setComment);
}, [cid]);
// ✅ Fix — use the hook
const { state, ...comment } = useComment({ commentCid: cid });
5. Syncing with external stores (use Zustand, not useEffect)
// ❌ Anti-pattern
const [theme, setTheme] = useState('light');
useEffect(() => {
const unsub = settingsStore.subscribe((s) => setTheme(s.theme));
return unsub;
}, []);
// ✅ Fix — use the Zustand store directly
const theme = useSettingsStore((s) => s.theme);
6. Sending analytics / logging (move to event handlers)
// ❌ Anti-pattern — fires on every render, not on user action
useEffect(() => {
logPageView(pageName);
}, [pageName]);
// ✅ Fix — call in the event handler or route change callback
const navigate = () => {
logPageView(pageName);
router.push(path);
};
7. Initializing global singletons (use module scope or lazy init)
// ❌ Anti-pattern
useEffect(() => {
initializeAnalytics();
}, []);
// ✅ Fix — module-level init (runs once on import)
if (typeof window !== 'undefined') {
initializeAnalytics();
}
Project-Specific Replacements
| useEffect pattern | Replace with |
|---|---|
| Fetch data | useComment, useFeed, useSubplebbit, etc. from bitsocial-react-hooks |
| Sync shared state | Zustand store in src/stores/ |
| Derive values from state | Calculate during render |
| Boolean loading/error flags | state field from bitsocial-react-hooks, or state machine in Zustand |
When useEffect IS Appropriate
Not every effect is wrong. Keep useEffect for:
- Subscribing to browser APIs (resize, intersection observer, etc.) with proper cleanup
- Synchronizing with non-React systems (third-party widgets, imperative DOM)
- Running code on mount that genuinely has no hook equivalent