← Apple Interview Insights

Apple·Frontend Engineer·Technical Phone Screen·Senior

SeniorPrefer not to say
May 2026

Summary

Apple frontend interview that was basically a deep dive on React hooks, nothing else. They wanted production experience, not textbook definitions, which I was not fully prepared for.

Questions Asked (6)

Q1

Walk through every React hook you've used in production. For each one, give a real use case and a bug you actually hit.

Technical Trade-offsAPI & IntegrationsSystem Design
Author's notes

This was the whole interview, basically.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Select 4-6 hooks you've genuinely used in production and for each, briefly describe the use case, then dive into a specific bug you encountered, how you diagnosed it, and the fix. Prioritize hooks that demonstrate depth (e.g., useEffect, useMemo, useCallback, useReducer, useContext, custom hooks) and tie bugs to real-world impact like performance or correctness. Keep the narrative structured and concise, showing both technical knowledge and debugging maturity.

Pro tip: Choose bugs that reveal a non-obvious React pitfall (e.g., stale closures, dependency array mistakes, or unnecessary re-renders) and explain how you used React DevTools or profiling to pinpoint the issue. This shows you don't just code—you debug systematically and understand the 'why' behind React's behavior.

1. Select and order hooks strategically

Pick 4-6 hooks you've truly used in production, ordering them from most to least complex or impactful. Avoid listing every hook you know; focus on ones where you have a compelling bug story.

2. Describe the use case succinctly

For each hook, give a one-sentence summary of the production scenario (e.g., 'useEffect for syncing data with a WebSocket connection in a dashboard').

3. Detail the bug and its symptoms

Explain the bug clearly: what went wrong, how it manifested (e.g., infinite loop, stale data, memory leak), and its impact on users or performance.

4. Explain diagnosis and fix

Walk through how you identified the root cause (e.g., using React DevTools, console logs, or code review) and the exact fix you applied, including any trade-offs.

5. Summarize the lesson learned

Conclude each hook's story with a key takeaway or best practice you now follow, demonstrating growth and deeper understanding.

Key Points to Mention

  • Specific hooks: useState, useEffect, useContext, useReducer, useMemo, useCallback, useRef, and custom hooks.
  • Common pitfalls: stale closures in useEffect, missing dependencies, overuse of useMemo/useCallback causing complexity, and improper cleanup.
  • Debugging tools: React DevTools Profiler, console logs, and breakpoints to trace re-renders and state changes.
  • Performance implications: how hooks affect rendering, memory, and user experience, with metrics if possible.
  • Trade-offs: when to use useMemo vs. useCallback, or useReducer vs. useState, and why you chose one over the other.
  • Production impact: quantify the bug's effect (e.g., 'caused 30% slower load time') and the improvement after the fix.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

What are the common mistakes people make with the useEffect dependency array?

Technical Trade-offs
Author's notes

I talked about stale closures and forgetting to include functions in the dep array.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by acknowledging that useEffect dependency array mistakes are common and can lead to bugs like stale closures, infinite loops, and unnecessary re-renders. Then, systematically explain the most frequent mistakes, why they happen, and how to avoid them, emphasizing the importance of understanding React's reconciliation and effect lifecycle. Conclude with best practices and tools for catching these issues.

Pro tip: Mention that using the exhaustive-deps ESLint rule is a good start, but it's not a silver bullet; sometimes you need to restructure your code or use useCallback/useMemo to stabilize dependencies. Also, highlight that understanding the 'why' behind the rule helps in making informed trade-offs.

1. Identify the common mistakes

List the typical errors: missing dependencies, unnecessary dependencies, incorrect dependencies (e.g., objects/functions recreated each render), and misunderstanding when the effect runs.

2. Explain the consequences

Describe the bugs each mistake causes: stale props/state, infinite loops, performance issues, and unpredictable behavior.

3. Discuss solutions and best practices

Offer ways to fix each mistake: using the exhaustive-deps lint rule, memoizing values with useCallback/useMemo, moving functions inside effects, and using refs for mutable values.

4. Highlight trade-offs and advanced considerations

Talk about when to intentionally omit dependencies (e.g., for one-time effects) and how to handle complex dependencies with custom hooks or reducers.

5. Summarize with a real-world example

Provide a concrete example (e.g., fetching data) that illustrates a common mistake and its fix, showing practical understanding.

Key Points to Mention

  • Missing dependencies leading to stale closures and outdated values.
  • Including unnecessary dependencies causing infinite loops or excessive re-renders.
  • Dependencies that change on every render (objects, arrays, functions) and how to stabilize them.
  • The exhaustive-deps ESLint rule and its limitations.
  • Using useCallback, useMemo, and useRef to manage dependencies.
  • The importance of understanding the effect's purpose and lifecycle.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

When does useMemo or useCallback actually help performance, and when is it just noise?

Technical Trade-offsRoot Cause Analysis
Author's notes

Blanked for a second on a concrete example.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by defining what 'helping performance' means in React—avoiding unnecessary re-renders or expensive recalculations—then explain that useMemo/useCallback only pay off when the cost of the memoization overhead is less than the cost of the work being memoized. Use concrete examples to illustrate when they are beneficial and when they are unnecessary noise.

Pro tip: Emphasize that premature optimization with useMemo/useCallback can actually hurt performance due to increased memory usage and dependency comparison overhead, and that profiling with React DevTools should guide their usage.

1. Clarify the purpose

Explain that useMemo memoizes a computed value and useCallback memoizes a function reference, both to maintain referential equality across renders.

2. Identify when they help

They help when passing callbacks or objects to optimized child components (React.memo, PureComponent) or when computing expensive values that would otherwise recalculate on every render.

3. Identify when they are noise

They are noise when used for cheap computations, when dependencies change frequently, or when the component rarely re-renders, as the overhead outweighs benefits.

4. Measure and decide

Use profiling tools to measure actual performance impact before adding memoization, and consider alternatives like restructuring components or lifting state.

Key Points to Mention

  • Referential equality and its role in React's reconciliation
  • React.memo and how it interacts with useCallback/useMemo
  • Cost of dependency array comparison vs. cost of re-computation
  • Common pitfalls: over-memoization, stale closures, and unnecessary dependencies
  • Alternatives: useReducer, state colocation, component composition
  • Profiling with React DevTools and the 'why-did-you-render' library

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

How do you use useRef beyond just DOM references? What's the difference between a DOM ref and storing an instance value?

Technical Trade-offs
Author's notes

Pretty clean answer here.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying that useRef returns a mutable object whose .current property persists across renders without causing re-renders. Then contrast DOM refs (attached to elements via the ref attribute) with instance values (stored in .current for any mutable data). Illustrate with practical examples like storing timers, previous values, or imperative handles.

Pro tip: Emphasize that useRef is not just for DOM—it's a general-purpose 'box' for values that shouldn't trigger re-renders. Mention that overusing it for state can lead to stale UIs, so use it judiciously.

1. Define useRef

Explain that useRef returns a mutable ref object with a .current property that persists for the full lifetime of the component.

2. DOM refs

Describe how DOM refs are attached to React elements via the ref attribute to access the underlying DOM node directly.

3. Instance values

Explain that you can store any mutable value in .current, such as timers, previous props/state, or third-party library instances, without triggering re-renders.

4. Key differences

Contrast DOM refs (read-only after mount, tied to element lifecycle) with instance values (fully mutable, independent of rendering).

5. Use cases & trade-offs

Provide examples like storing interval IDs, tracking previous values, or integrating with non-React libraries, and note when to prefer state instead.

Key Points to Mention

  • useRef returns a mutable object with .current that persists across renders without causing re-renders.
  • DOM refs are attached to elements via the ref attribute and give access to the DOM node.
  • Instance values can store any data (e.g., timers, previous values, mutable objects) and are not tied to DOM.
  • DOM refs are typically read-only after mount; instance values are fully mutable.
  • Common use cases: storing interval/timeout IDs, tracking previous props/state, integrating with third-party libraries.
  • Trade-off: using refs for state can lead to stale UI; use state for values that should trigger re-renders.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q5

Describe a custom hook you've written and why it was worth abstracting.

Technical Trade-offsSystem Design
Author's notes

Talked about a useDebounce hook and a useOutsideClick hook.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Choose a custom hook that solved a real, recurring problem in your app, and structure your answer around the problem, the abstraction, and the measurable benefits. Emphasize the trade-offs you considered and why the abstraction was worth it, especially in terms of reusability, testability, and maintainability.

Pro tip: Quantify the impact where possible (e.g., reduced code duplication by X%, decreased bug reports by Y%) and mention how you ensured the hook remained flexible without becoming over-abstracted.

1. Set the context

Briefly describe the problem or repeated pattern that motivated the custom hook, including the specific pain points (e.g., duplicated logic, complex state management).

2. Explain the hook's design

Outline the hook's API, its inputs and outputs, and how it encapsulates the logic. Highlight any key decisions like parameterization or return values.

3. Discuss the benefits

Detail the concrete advantages: reduced duplication, improved readability, easier testing, and consistent behavior across components.

4. Address trade-offs and alternatives

Acknowledge any downsides (e.g., added indirection, potential over-abstraction) and explain why you chose a custom hook over alternatives like HOCs or render props.

5. Share the outcome and lessons

Summarize the impact (e.g., time saved, fewer bugs) and what you learned about abstraction, such as when to extract a hook and when to keep logic local.

Key Points to Mention

  • Reusability: how the hook eliminated duplicated logic across multiple components.
  • Testability: how the hook made unit testing easier by isolating logic.
  • Maintainability: how changes now only need to be made in one place.
  • Trade-offs: potential downsides like over-abstraction or added complexity.
  • Alternatives: why a custom hook was better than HOCs, render props, or utility functions.
  • Impact: quantifiable results such as reduced lines of code or fewer bugs.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q6

When would you reach for useReducer instead of useState, and how does that interact with useContext?

Technical Trade-offsSystem Design
Author's notes

Said useReducer makes sense when state transitions have logic that needs to be explicit and testable, or when next state depends on previous state in complex ways.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by defining clear criteria for when useReducer is preferable to useState, such as complex state logic, multiple sub-values, or frequent updates. Then explain how combining useReducer with useContext enables a scalable state management pattern that avoids prop drilling and centralizes dispatch logic. Emphasize that this pattern is not a replacement for Redux but a lightweight alternative for medium-complexity apps.

Pro tip: Mention that useReducer + useContext can cause unnecessary re-renders if the context value changes frequently, and suggest splitting contexts or using memoization to optimize performance. This shows you understand real-world trade-offs beyond just API differences.

1. Define useReducer use cases

List scenarios where useReducer shines: complex state transitions, state objects with multiple fields, next state depends on previous, and when you want to centralize update logic in a reducer function.

2. Compare with useState

Contrast with useState: simpler for independent primitive values, but becomes unwieldy when managing interrelated state or when multiple event handlers need to update the same state in different ways.

3. Explain useContext integration

Describe how to create a context that provides both the state and the dispatch function from useReducer, allowing deeply nested components to read state and dispatch actions without prop drilling.

4. Discuss trade-offs and performance

Acknowledge that context triggers re-renders in all consumers when the value changes, and suggest optimizations like splitting state and dispatch into separate contexts or using useMemo.

5. Provide a concrete example

Walk through a brief example, such as a todo app or a multi-step form, where useReducer + useContext simplifies state management compared to useState alone.

Key Points to Mention

  • Complex state logic with multiple sub-values or nested objects
  • State transitions that depend on previous state or require actions
  • Avoiding prop drilling by combining with useContext
  • Performance considerations: context re-renders and memoization
  • When to choose useReducer over useState (and vice versa)
  • Real-world example like a shopping cart or form wizard

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.