| name | ghcopilot-hub-react |
| description | React 19 patterns with Compiler-aware guidance, composition, refs, and effects. Trigger: When working with React components (.tsx, .jsx), effects, refs, context APIs, or render performance/memoization decisions.
|
| license | Apache-2.0 |
| metadata | {"author":"jmgomezdev","version":"1.0"} |
React 19 + Compiler Patterns
This skill is optimized for React 19 projects and prioritizes decision quality over cookbook snippets.
Activation Gates (MANDATORY)
Before applying recommendations, choose the path below.
If the required reference is not loaded, do not give prescriptive advice for that area.
Symptom Router (Fast Path)
Pair with TypeScript
When working with React, always load both this skill and ghcopilot-hub-typescript together. TypeScript patterns (type-first
development, discriminated unions, Zod validation) apply to React code.
React Compiler
Impact: CRITICAL
Compiler guidance is valid only when compiler activation is verified.
Requires:
Fallback if not verified:
- Keep existing manual
useMemo / useCallback / React.memo
- Prefer targeted profiling before removing memoization
Use plain code by default only after verification gate passes. For full before/after examples and edge cases, read
references/react-compiler.md.
See references/react-compiler.md for verification and edge cases.
React 19 API Changes
Impact: MEDIUM
Apply these recommendations only when the project runtime/toolchain supports them. If support is uncertain, use the
fallback and avoid forced migration advice.
ref as Regular Prop (No forwardRef)
Requires React 19-compatible setup.
Fallback:
- If project is on React 18, keep
forwardRef.
const ComposerInput = forwardRef<HTMLInputElement, Props>((props, ref) => {
return <input ref={ref} {...props} />;
});
function ComposerInput({ ref, ...props }: Props & { ref?: React.Ref<HTMLInputElement> }) {
return <input ref={ref} {...props} />;
}
use() Instead of useContext()
Use with caution and only when project tooling/runtime fully supports this pattern.
Fallback:
useContext(MyContext) is valid and preferred for compatibility-sensitive codebases.
const value = useContext(MyContext);
const value = use(MyContext);
State & Composition Baselines
Keep baseline React guidance in references to preserve context budget.
Refs & Effects Rules
Impact: CRITICAL
Core Principle: Effects Are Escape Hatches
Effects let you "step outside" React to synchronize with external systems. Most component logic should NOT use
Effects. Before writing an Effect, ask: "Is this syncing with an external system?"
External systems include WebSocket connections, browser APIs, third-party libraries, DOM measurements, and timers.
Not external systems: props, state, derived values, and user events.
Before Writing useEffect
Check each case before reaching for an Effect:
- Transforming data? → Compute during render. Use
useMemo only if the computation is expensive.
- Responding to a user event? → Put the logic in the event handler.
- Resetting state on prop change? → Use the
key prop.
- Fetching data? → In SPAs, prefer TanStack Query. In RSC frameworks such as Next.js App Router, fetch on the server first. If
useEffect is unavoidable in a client boundary, include cleanup.
- Notifying a parent? → Call the callback in the event handler or make the component controlled.
- Chaining updates from one cause? → Collapse the cascade into one event handler or transition path.
- Subscribing to external store state? → Use
useSyncExternalStore.
If none of the cases above apply and the answer is still "yes, external system," then useEffect is the right tool.
When to Use Effects
Effects are for synchronizing with external systems:
- Subscribing to browser APIs (WebSocket, IntersectionObserver, resize)
- Connecting to third-party libraries not written in React
- Setting up/cleaning up event listeners on window/document
- Controlling non-React DOM elements (video players, maps)
When NOT to Use Effects
useEffect(() => {
setFullName(firstName + " " + lastName);
}, [firstName, lastName]);
const fullName = firstName + " " + lastName;
useEffect(() => {
setComment("");
}, [userId]);
<Profile userId={userId} key={userId} />;
useEffect(() => {
if (product.isInCart) {
showNotification("Added to cart");
}
}, [product]);
function handleAddToCart() {
addToCart(product);
showNotification("Added to cart");
}
See references/effects-patterns.md for advanced patterns and useEffectEvent
fallbacks.
Don't Read/Write Refs During Render
function MyComponent() {
const myRef = useRef(null);
myRef.current = 123;
return <h1>{myOtherRef.current}</h1>;
}
function MyComponent() {
const myRef = useRef<number | null>(null);
useEffect(() => {
myRef.current = 123;
}, []);
const handleClick = () => {
console.log(myRef.current);
};
}
Additional baseline rules
For custom hooks naming, lifecycle anti-patterns, and conditional rendering basics, load
references/common-mistakes.md.
Decision Tree
When deciding how to implement logic:
- Need to respond to user interaction? → Use event handler
- Need computed value from props/state? → Calculate during render; use
useMemo only if it is expensive
- Need to reset state on prop change? → Use
key prop
- Need data fetching? → In SPAs, prefer TanStack Query; in RSC frameworks such as Next.js App Router, fetch in Server Components or server utilities first; use Effect only as a client fallback with cleanup
- Need to notify a parent about an interaction? → Call the callback in the event handler
- Need to subscribe to external store state? → Use
useSyncExternalStore
- Need to synchronize with external system? → Use Effect with cleanup
- Need mutable value that doesn't trigger render? → Use ref
- Need perf advice around memoization? → Load
react-compiler.md first, verify compiler, then decide
- Need non-reactive logic inside Effect? → Load
effects-patterns.md, prefer fallback-safe approach if
useEffectEvent is unavailable
Resources