Routing & Data-fetching
The layer between your components and the outside world: client-side routers, HTTP and GraphQL clients, caching libraries, and form and validation utilities. Front-end interviews spend a lot of time here because it is where most real application complexity actually lives.
on this pageshowhide
explore
- React Router28 questions
- Route Configuration5 questions
- Nested and Dynamic Routes5 questions
- Navigation and Links5 questions
- Loaders and Actions5 questions
- Params and Search Params4 questions
- Route Protection4 questions
- TanStack Router5 questions
- Vue Router36 questions
- Setup & History Modes5 questions
- Param Matching & Props6 questions
- Nested & Named Views5 questions
- Links & Programmatic Navigation5 questions
- Navigation Guards5 questions
- Lazy & Runtime Routes5 questions
- Typed File Routes5 questions
- TanStack Query27 questions
- Query Keys & Factories4 questions
- Caching & Staleness5 questions
- Query Lifecycle & Status5 questions
- Mutations4 questions
- Invalidation & Refetching5 questions
- Pagination & Infinite Queries4 questions
- SWR5 questions
- Axiosempty
- Apollo33 questions
- Queries and Mutations6 questions
- Normalized Cache5 questions
- Fragments5 questions
- Subscriptions6 questions
- Local State and Reactive Vars5 questions
- Links and Error Handling6 questions
- Relay6 questions
- urql6 questions
- React Hook Form6 questions
- Formik6 questions
- VeeValidate5 questions
- FormKitempty
- Vuelidateempty
questions
163 · 11 sectionsIn React Router 7's data mode, what do a route's loader and action functions receive, and how does a component read what each returned?
basics
~20 sIn React Router 7, loader and action are route-object functions that each receive a Fetch Request and the matched params. The loader runs before the route renders and is read with useLoaderData; the action handles non-GET submissions and is read with useActionData.
In React Router v7, what type are the values useParams returns, and what must you do before using :productId as a number?
basics
~20 suseParams values are strings or undefined, decoded from the URL and never coerced. A :productId segment matches any text, so parse it, check the result, and render a not-found or error state when it is missing or invalid.
Compared with React Router's useSearchParams, how does TanStack Router's validateSearch keep a product list's page and filter search params typed and refactor-safe?
basics
~20 sReact Router's useSearchParams yields URLSearchParams strings that each reader parses. TanStack Router parses the query JSON-first and runs the route's validateSearch once, so Route.useSearch() is typed and every Link or navigate writing search is checked against that schema.
In TanStack Router, what is the difference between file-based routes generated by the bundler plugin and code-based routes built with createRoute?
basics
~20 sBoth produce the same typed route tree. File-based routing lets the TanStack Router bundler plugin generate routeTree.gen.ts from files that call createFileRoute; code-based routing builds the tree by hand with createRootRoute, createRoute({ getParentRoute, path }) and addChildren.
In TanStack Router, how do beforeLoad and router context let an _authenticated layout route gate its children using auth state that lives in a React hook?
basics
~20 sDeclare the context type with createRootRouteWithContext, pass the hook's value through <RouterProvider context={{ auth }}>, and read context.auth in the layout's beforeLoad, throwing redirect() when signed out. beforeLoad runs parent-first before loaders; call router.invalidate() when auth changes.
In TanStack Router, how does <Link to="/posts/$postId"> get checked at compile time, and what does registering the router through the Register interface do?
basics
~20 sThe route tree's inferred type lists every path with its params and search types. Declaring interface Register { router: typeof router } for '@tanstack/react-router' hands that type to the global Link and hooks, so a bad to, params or search fails to compile.
A TanStack Router /products loader reads the page from location.search, and changing ?page=2 keeps showing page 1's data; why, and how do loaderDeps and staleTime fix it?
basics
~20 sTanStack Router caches loader results per route match, keyed by route, path params and loaderDeps — not the search string. A search-only change keeps the same match, so the loader is not re-run. Declaring loaderDeps for page gives each page its own entry.
In Vue Router 5 file-based routing, how do src/pages files become routes, and what do index.vue, [slug].vue and [...path].vue generate?
basics
~10 sThe vue-router/vite plugin scans src/pages and generates the route records, which you import from vue-router/auto-routes. index.vue maps to its folder's path, [slug].vue to a :slug param, and [...path].vue to the catch-all /:path(.*).
In Vue Router 5, how do you write a `router.beforeEach` guard that uses `to.meta.requiresAuth` to send signed-out HR-portal users to `/login` with their destination?
basics
~20 sRegister router.beforeEach((to) => …) and, when to.meta.requiresAuth is set and nobody is signed in, return { name: 'login', query: { redirect: to.fullPath } }. Returning nothing lets every other navigation through; keep the login route itself unprotected.
In Vue Router 5, how do you lazy-load a dashboard route's component, and what breaks if you write `component: import('./Billing.vue')` without the arrow function?
basics
~20 sGive the route a loader, component: () => import('./Billing.vue'); the router calls it on first entry, waits for it and caches the result. Without the arrow the import runs at startup, and development warns that production will break.
In Vue Router 5, how does a route record with path '/products/:id' match URLs, and how does a script setup component read the id?
basics
~10 sThe :id segment matches exactly one non-empty path segment, so /products/42 matches and /products/42/reviews does not; a component reads it as useRoute().params.id, a decoded string.
In TanStack Query v5, how do you make a query for a user's projects wait until another query has returned that user's id?
basics
~20 sGive the projects query enabled: !!userId and put userId in its query key. While disabled it sits in status pending with fetchStatus idle, and it fetches on its own as soon as the id arrives.
In TanStack Query v5, after a mutation that creates a todo succeeds, how do you make the todo lists on screen show it?
basics
~10 sIn the mutation's onSuccess, call queryClient.invalidateQueries({ queryKey: ['todos'] }). Every query whose key starts with 'todos' is marked stale; those currently rendered refetch in the background at once, the rest refetch when next mounted.
In TanStack Query v5, what is the difference between the mutate and mutateAsync functions that useMutation returns?
basics
~20 smutate starts the mutation and returns nothing; errors are caught internally and surface through callbacks and the hook's error state. mutateAsync returns a promise that resolves with the data or rejects with the error, so you must catch it yourself.
In TanStack Query v5, how does useInfiniteQuery decide which page to fetch next, and how does it know there are no more pages?
basics
~10 suseInfiniteQuery fetches the first page with initialPageParam, then asks getNextPageParam(lastPage, allPages, lastPageParam, allPageParams) for each next param. Returning undefined or null sets hasNextPage to false. Pages accumulate in data.pages and data.pageParams.
In TanStack Query v5, a todo list keyed ['todos'] has a queryFn reading a status filter; why does a filter change show the wrong list?
basics
~20 sThe key is the cache identity, and ['todos'] never changes, so every filter shares one entry and a filter change starts no fetch. Put every variable the queryFn uses into the key, such as ['todos', 'list', { status }].
In SWR 2, how do null, function and array keys change what useSWR fetches, and what does the fetcher receive for an array key?
basics
~20 sA null or falsy key fetches nothing. A function key is called, and fetches nothing if it throws or returns a falsy value. Array and object keys are hashed stably and reach the fetcher as one argument, not spread.
In SWR, how do you use mutate to show a user's new display name in the header immediately and roll it back if saving fails?
basics
~20 sCall mutate for '/api/user' with the save promise and optimisticData set to the edited user. The header updates at once; if the promise rejects, rollbackOnError (default true) restores the previous data, and revalidate (default true) refetches afterwards.
Compared with TanStack Query, what does SWR deliberately leave out of its cache model, and how does that change the code you write?
basics
~20 sSWR has no freshness setting like staleTime, no automatic eviction like gcTime, and no AbortSignal for the fetcher. You turn revalidation off per hook where it is not needed, clear the cache yourself, and handle cancellation in your own code.
After one user logs out and another logs in, an SWR app briefly shows the previous user's profile and orders; why, and how do you clear SWR's cache correctly?
basics
~20 sSWR's cache outlives the session, and '/api/user' is the same key for both users, so the new user first sees the old cached data. On logout call unload({ revalidate: false }) (SWR 2.5+), or give each session its own cache provider.
In Apollo Client 4, why does ProductCard declare its own fragment, and how does that fragment reach the product listing page's query?
basics
~10 sProductCard declares a fragment so the fields it renders live beside the code that renders them. The listing query spreads ...ProductCardFragment and interpolates its definition, so one request fetches every card's fields.
In Apollo Client 4, what is a reactive variable created with makeVar, and how would you use one for a shop's cart drawer open flag?
basics
~20 sA reactive variable is the function makeVar(initialValue) returns: call it with no argument to read, with one argument to write. It lives outside the cache, and components that read it through useReactiveVar re-render when it changes.
In Apollo Client 4, how does InMemoryCache store an author shown on fifty feed posts, and what breaks if the query omits the author's id?
basics
~20 sInMemoryCache stores each object with __typename and id once, under a cache ID such as Author:42, and every post references it. Without id in the feed query, each post embeds its own author copy and renames stop propagating.
In Apollo Client 4, what does useQuery return for an issue list while loading, on error and on success, and how do you render each?
basics
~20 sApollo Client 4's useQuery returns loading, error, data and dataState, which can overlap: cached rows arrive with loading true, and a failed refetch keeps rows beside error. Render data when present, else the error or a spinner.
In Apollo Client 4, what does the useSubscription hook give a notification badge, and when does the badge re-render?
basics
~20 suseSubscription, imported from @apollo/client/react, returns loading, data, error and restart. loading stays true until the first event arrives; after that, data holds only the latest event, and the component re-renders as each pushed event lands.
What does the relay-compiler do with the graphql-tagged queries and fragments in a Relay app, and why must it run before the app works?
basics
~20 sThe relay-compiler validates every graphql tag against the schema ahead of time and writes a generated artifact per query or fragment: runtime metadata, query text and types. A Babel plugin swaps each tag for its artifact, so uncompiled tags throw.
In Relay, why can't a parent component read the fields its child's useFragment fragment selects, even though they arrive in the same response?
basics
~20 sRelay's data masking: useFragment returns only the fields its own fragment selected. A spread child fragment reaches the parent as an opaque fragment reference, which the child passes to useFragment to read its fields from the store.
In Relay, how do useLazyLoadQuery and usePreloadedQuery with useQueryLoader differ in when an article page's query starts fetching?
basics
~20 suseLazyLoadQuery starts fetching only when its component renders, so code loading and parent renders delay it and nested lazy queries waterfall. With useQueryLoader, an event handler or route transition calls loadQuery first, and usePreloadedQuery later reads that reference, suspending until it resolves.
With Relay's usePaginationFragment, what must a news article's comment-thread fragment declare, and how does loadNext add the next page?
basics
~20 sThe fragment needs @argumentDefinitions for count and cursor, @refetchable(queryName) so the compiler generates a pagination query, and @connection(key) on the comments field. loadNext(n) sends that query from the current end cursor, and Relay appends the new edges to the stored connection.
In Relay, a news article's like button and add-comment form both use useMutation; how do the like count and the comment thread update, instantly and after the server replies?
basics
~20 sRelay merges payload objects into stored records by id, so a like payload selecting likeCount updates every reader; an optimisticResponse shows it instantly and is rolled back on reply. A new comment is inserted with @prependEdge and the thread's connection id.
In urql 5 for React, how do you create and provide a Client, and what does exchanges: [cacheExchange, fetchExchange] do?
basics
~20 sAn urql Client is built with createClient({ url, exchanges }) and handed to components through Provider. The required exchanges array is a pipeline: cacheExchange answers from the document cache, fetchExchange sends everything else over HTTP.
In urql, what do the four requestPolicy values do, and when would a storefront screen pick cache-and-network over the default?
basics
~10 surql's requestPolicy is cache-first by default, returning a cached result or fetching once. cache-and-network returns the cached result marked stale and refetches, network-only always fetches, and cache-only never sends a request.
In urql's default document cache, why does an empty cart keep showing no items after an addToCart mutation succeeds, and how do you fix it?
basics
~20 surql's document cache invalidates cached queries whose results contained a __typename that the mutation result contains. An empty cart's lines list carries no CartLine typename, so nothing links it to addToCart; additionalTypenames adds that link.
When an urql storefront moves from the document cache to Graphcache, what do its keys, updates and optimistic options configure, and what breaks without them?
basics
~10 sGraphcache's keys say how to identify entities without an id, updates.Mutation holds updaters for list and link changes a mutation result cannot express, and optimistic returns a temporary result applied until the server answers.
For a React storefront team choosing between urql and Apollo Client 4, when is urql the better fit, and what does the team give up?
basics
~20 surql fits when a team wants a small, exchange-based client that starts with a simple document cache and adds Graphcache only when shared entities demand it. The team gives up built-in local state and Apollo's freedom to write to the cache anywhere.
In React Hook Form, what does register('email', { required: true }) give an input, and what does handleSubmit do before calling your callback?
basics
~20 sIn React Hook Form, register returns name, ref, onChange and onBlur to spread onto a native input. handleSubmit prevents the default submit, validates every field, then calls onValid(data) only when no errors remain, otherwise onInvalid(errors).
In a React Hook Form signup form, how do you connect a controlled date-picker component that takes value and onChange but exposes no native input?
basics
~10 sWrap the date-picker in React Hook Form's Controller (or call useController) with name, control and rules. Its render prop supplies field.value, field.onChange, field.onBlur and field.ref, which you map onto the picker's own props.
Why does typing into a React Hook Form input usually not re-render the form component, when the same keystroke in a Formik form does?
basics
~20 sReact Hook Form leaves registered values in the DOM and its own store, and re-renders only for formState you read. Formik keeps values in the form owner's state, so each keystroke re-renders that component and its children.
In React Hook Form, what do the useForm options mode and reValidateMode control, and what are their defaults?
basics
~20 sIn React Hook Form, mode sets when fields validate before the first submit (default 'onSubmit'); reValidateMode sets when they validate after a submit (default 'onChange'). By default nothing validates while typing until the user has submitted once.
A React Hook Form signup form renders useFieldArray phone rows with key={index}, and after removing a middle row, row-level state sticks to the wrong numbers — why, and what is the fix?
basics
~20 sReact keeps component state and DOM nodes by key, so with index keys a removal makes the surviving rows inherit the removed row's state. useFieldArray gives every row a stable field.id; use key={field.id}, as the documentation requires.
In Formik 2, what do <Formik>, <Form>, <Field> and <ErrorMessage> each wire up, and when would you call useFormik directly instead?
basics
~20 sIn Formik 2, <Formik> owns the form state and provides it through context; <Form> wires submit and reset; <Field> binds an input to values, handleChange and handleBlur; <ErrorMessage> shows a touched field's error. useFormik returns the same state without context.
In Formik 2, a field's error already exists in errors while the user types, yet no message shows until they leave the field — why?
basics
~20 sFormik 2 validates the whole form on every change and blur by default, so errors fills in while the user types. touched.field is set only by blur or submit, and the usual display gate — including ErrorMessage — needs both.
A Formik 2 form's submit button, disabled by isSubmitting, stays disabled forever after the first submit — what in onSubmit causes that?
basics
~10 sFormik 2 resets isSubmitting only when onSubmit returns a promise, once it settles. A synchronous onSubmit, or one that starts a request without returning it, leaves isSubmitting true until you call setSubmitting(false).
In Formik 2, how do you build a reusable custom input with useField, and what do the three values it returns hold?
basics
~20 sIn Formik 2, useField(name) returns [field, meta, helpers]: field holds name, value, onChange and onBlur to spread onto an input; meta holds value, error, touched and initial values; helpers holds setValue, setTouched and setError for non-event widgets.
A Formik 2 edit-profile form renders before the user record loads and stays empty after it arrives — how do you fix it, and what does enableReinitialize risk?
basics
~20 sFormik 2 reads initialValues once, at mount. enableReinitialize resets the form whenever initialValues changes by deep equality, which discards unsaved edits if the loaded data changes again; rendering after load or keying by user id avoids that.
With VeeValidate 4's useForm and defineField, how do you bind a sign-up form's email input and show its validation error?
basics
~10 sCall useForm with a schema, then const [email, emailAttrs] = defineField('email'). Bind the input with v-model="email" and v-bind="emailAttrs", and render errors.email, the field's first error message.
In VeeValidate 4 with a toTypedSchema Zod schema, why are form values typed partial while handleSubmit's callback gets required fields, and when does the callback not run?
basics
~20 stoTypedSchema tells VeeValidate the schema's input type, a deep partial of what users are filling in, and its output type, what a valid parse returns. handleSubmit validates everything first and only calls your callback, with the output, when the form is valid.
In a VeeValidate 4 sign-up form, how do you render a repeatable phone list with useFieldArray, and why key rows by field.key but name them by index?
basics
~20 suseFieldArray('phones') returns read-only fields plus helpers such as push and remove. Key the v-for on field.key, a stable generated id, but name each input phones[idx], because the form stores an array and paths are positional.
In VeeValidate 4, why does a sign-up email field bound with defineField show an error on the first keystroke, and how do you make it validate on blur instead?
basics
~20 sdefineField's model validates on every update because validateOnModelUpdate defaults to true, and v-model updates on each keystroke. Pass defineField('email', { validateOnModelUpdate: false }) and the field validates on blur and change instead, which stay on by default.
In a VeeValidate 4 sign-up form validated by one Zod schema, why does an async username-availability refine fire on keystrokes in other fields, and how do you contain it?
basics
~20 sWith a form-level schema, validating any field parses the whole schema, so an async username refine runs whenever email or password validate. Cache the lookup per username, make the field lazy, and show meta.pending while it runs.