Structure that scales
Good React code has one source of truth per piece of state, components that compose cleanly and context used sparingly. Interviewers look for those habits in your examples.
- Data flowLifting state and controlled components.
- ReuseComposition, children and custom hooks.
- ResilienceContext, reducers, portals and error boundaries.
Beyond hooks, interviewers want to know how you structure components: where state lives, how data flows down and events flow up, and how you avoid prop drilling without over-engineering. These patterns are the difference between a demo and a maintainable app.
1. What does “lifting state up” mean?
When two siblings need the same data, move the state to their closest common parent and pass it down as props, with callbacks for changes. One source of truth keeps them in sync.
function Converter() {
const [inr, setInr] = useState(0);
return (
<>
<AmountInput label="INR" value={inr} onChange={setInr} />
<AmountInput label="USD" value={(inr / 83).toFixed(2)} onChange={usd => setInr(usd * 83)} />
</>
);
}2. How does composition with children replace inheritance?
React recommends composition: components accept children or other elements as props and arrange them. Layouts, modals and cards become reusable containers without class hierarchies.
function Card({ title, actions, children }) {
return (
<section className="card">
<header><h3>{title}</h3>{actions}</header>
<div className="card__body">{children}</div>
</section>
);
}
<Card title="Profile" actions={<button>Edit</button>}>
<ProfileDetails user={user} />
</Card>3. When should you use the Context API?
For values many components at different depths need and that change rarely — the current user, theme, language, feature flags. Context is not a performance tool: every consumer re-renders when the value changes, so split contexts and memoise the value. For frequently changing global state, use a store.
const AuthContext = createContext(null);
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const value = useMemo(() => ({ user, login: setUser, logout: () => setUser(null) }), [user]);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
export const useAuth = () => {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error('useAuth must be used inside AuthProvider');
return ctx;
};4. useState or useReducer?
useState for independent simple values. useReducer when several values change together or the next state depends on an action type — a cart, a multi-step form, a data loader with loading/error/data. The reducer is a pure function, easy to test on its own.
function cartReducer(state, action) {
switch (action.type) {
case 'add':
return { ...state, items: [...state.items, action.item] };
case 'remove':
return { ...state, items: state.items.filter(i => i.id !== action.id) };
case 'clear':
return { ...state, items: [] };
default:
return state;
}
}
const [cart, dispatch] = useReducer(cartReducer, { items: [] });5. How do you build a reusable controlled input component?
Accept value and onChange from the parent, forward other props to the native input, connect the label with htmlFor/id (or useId) and show errors accessibly with aria-describedby.
function TextField({ label, error, ...inputProps }) {
const id = useId();
return (
<div className="field">
<label htmlFor={id}>{label}</label>
<input id={id} aria-invalid={!!error} aria-describedby={error ? `${id}-err` : undefined} {...inputProps} />
{error && <p id={`${id}-err`} className="field__error">{error}</p>}
</div>
);
}6. What are error boundaries?
Components that catch errors thrown while rendering their children and show a fallback instead of a blank page. They are still written as class components (or with a small library) and do not catch errors in event handlers or async code — handle those with try/catch.
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() { return { hasError: true }; }
componentDidCatch(error, info) { reportError(error, info); }
render() {
return this.state.hasError ? <p>Something went wrong. Please refresh.</p> : this.props.children;
}
}7. What are portals used for?
createPortal renders children into a different DOM node — typically document.body — while keeping them in the React tree for context and events. Used for modals, tooltips and toasts that must escape parent overflow or stacking contexts.
function Modal({ open, onClose, children }) {
if (!open) return null;
return createPortal(
<div className="backdrop" onClick={onClose}>
<div role="dialog" aria-modal="true" onClick={e => e.stopPropagation()}>{children}</div>
</div>,
document.body,
);
}8. How do you decide where a piece of state should live?
Keep it as close as possible to where it is used. If only one component needs it, local state. If siblings need it, the common parent. If it describes the URL (filters, page, selected tab), put it in the URL. Server data belongs in a data-fetching cache. Only truly global client state goes in context or a store.
Remember
Key points
- State close to its use
Lift only when needed.
- Composition over inheritance
Pass children and elements.
- Context for rare changes
Memoise and split providers.
- Reducers for related state
Pure and easy to test.
Interview drill
Follow-up questions
What the interviewer asks after your first answer. Turn on practice mode, answer each one aloud, then reveal.
-
1 What is prop drilling and how do you avoid it? Basic
Passing props through many components that do not use them. Avoid it with composition (pass components as children), context, or a store — in that order of preference.
-
2 What is a higher-order component? Intermediate
A function that takes a component and returns an enhanced one (for example
withAuth(Page)). Custom hooks have largely replaced HOCs for sharing logic. -
3 What is the render props pattern? Intermediate
Passing a function as a prop that returns UI, so a component can share behaviour while the caller decides what to render. Hooks now cover most of these cases.
-
4 What does forwardRef do, and what changed in React 19? Advanced
It let function components receive a
reffrom parents. In React 19,refis a regular prop for function components, so forwardRef is no longer needed in new code. -
5 How do you reset a component's state when a prop changes? Intermediate
Give it a
keybased on that prop — React remounts it with fresh state when the key changes. -
6 What are compound components? Advanced
A set of components that work together and share state through context, like
<Tabs><Tabs.List><Tabs.Panel>, giving flexible markup with a simple API.