Capítulo 39 de 80
Three automatic mechanisms keep re-renders minimal — structural sharing (stable references for unchanged data), tracked properties (re-render only on properties actually read), and select (subscribe to a derived subset) — but object rest destructuring silently defeats tracked-properties, and an inline select function silently defeats its own memoization.
structuralSharing: false or a custom diff function.useQuery/useInfiniteQuery/useMutation (and the array from useQueries) is a new reference every render — only data itself benefits from structural-sharing stability.isFetching/isStale changing doesn't re-render a component that never reads them. Configurable via notifyOnChangeProps (set to 'all' to disable). Object rest destructuring silently disables this — the ESLint rule no-rest-destructuring exists specifically to catch this.select: subscribes the component to a derived value instead of the raw data, re-rendering only when that derived value changes — e.g. useTodos((data) => data.length) re-renders only on count change, not on unrelated field edits.select error handling: select operates only on already-successful cached data — it is not a place to throw; a select that throws internally results in data: undefined with isSuccess: true, which is a confusing state. Validate/error in queryFn (to genuinely fail the query) or outside the hook, not inside select.select memoization: re-runs only if the select function's own reference changes or data changes — an inline arrow function re-creates on every render, so it re-runs every render too. Fix with useCallback or a module-level stable function reference.// Inline select — re-runs every render (new reference each time)
export const useTodoCount = () => useTodos((data) => data.length)
// Stable reference — only re-runs when `data` actually changes
const selectTodoCount = (data) => data.length
export const useTodoCount = () => useTodos(selectTodoCount)
select (loses memoization) and a hoisted stable reference (keeps it).useQuery result if you want tracked-properties re-render skipping to keep working — enable the no-rest-destructuring ESLint rule to catch this automatically.select functions to a stable reference (module scope or useCallback) — an inline one defeats its own memoization every render.select — it can only degrade to data: undefined silently, not fail the query the way a queryFn throw does.no-rest-destructuring rule enforcing the tracked-properties caveat.