SSR: Effects don’t run on the server. This means that initial server-rendered HTML will only include a loading state with no data. The client computer will have to download all JavaScript and render our app only to discover that now it needs to load the data. This is not very efficient.
Creates Network waterfalls: Fetching directly in Effects makes it easy to create “network waterfalls”. You render the parent component, it fetches some data, renders the child components, and then they start fetching their data. If the network is not very fast, this is significantly slower than fetching all data in parallel.
Avoids Preloading and caching: Fetching directly in Effects usually means you don’t preload or cache data. For example, if the component unmounts and then mounts again, it would have to fetch the data again.
It’s not very ergonomic. There’s quite a bit of boilerplate code involved when writing fetch calls in a way that doesn’t suffer from bugs like race conditions.
If you use a framework, use its built-in data fetching mechanism. Modern React frameworks have integrated data fetching mechanisms that are efficient and don’t suffer from the above pitfalls.
Otherwise, consider using or building a client-side cache. Popular open-source solutions include React Query, useSWR, and React Router 6.4+. You can build your solution too, in which case you would use Effects under the hood but also add logic for deduplicating requests, caching responses, and avoiding network waterfalls (by preloading data or hoisting data requirements to routes).
You can continue fetching data directly in Effects if none of these approaches suit you.
If you need to load a user's profile when a component mounts, how would you structure the fetch using useEffect? What happens if you put the fetch call directly in the component body?
What will the UI show if the fetch promise resolves after the component has unmounted, and how can you prevent the warning?
If you forget to include a dependency array, how often will the fetch run and why?
You added a fetch inside useEffect that depends on a prop ID, but the request fires twice on mount. Walk me through why that might happen and how you'd fix it.
During a code review you see a teammate fetching data inside a useMemo. Explain why that is problematic and what you would recommend instead.
Our component sometimes shows stale data after rapid prop changes. How does the closure captured by useEffect contribute, and how would you address it?
We have a list component that fetches pages as the user scrolls. Discuss the tradeoffs of initiating fetches inside useEffect versus using a custom hook or external state manager, especially regarding cancellation and testability.
In a large codebase we want to enforce a rule that data fetching should happen in a separate service layer, not directly in useEffect. How would you design an abstraction to satisfy that while keeping components simple?
When server‑side rendering, fetching inside useEffect doesn't run on the server. How would you adapt the data‑fetching strategy to support both SSR and client hydration without duplicating logic?
Our organization is migrating from class components to functional components across many services. The existing codebase has data fetching in componentDidMount and componentDidUpdate. Outline a migration plan that ensures consistent behavior, handles race conditions, and integrates with our global caching layer.
We need to decide whether to centralize all data fetching in a GraphQL client versus allowing individual components to fetch via useEffect. What are the long‑term maintenance, performance, and team autonomy implications of each approach?
Given a micro‑frontend architecture where each team owns a slice of UI, how would you establish a contract for data fetching that avoids duplicated requests and respects bundle‑size constraints?