Redux Interview Questions and Answers

useSelector is a React-Redux hook that allows a component to read data from the Redux store.
It subscribes the component to the store, and the component re-renders whenever the selected state changes.

useSelector accepts a selector function that returns the desired portion of state.

Example:

const count = useSelector((state) => state.counter.value);

Here:

  • state = entire Redux store
  • state.counter.value = specific slice of data needed
  • Component re-renders only when this value changes

How useSelector Works Internally

  1. Component calls useSelector with a selector function
  2. useSelector subscribes to the Redux store
  3. Whenever the store updates:
    • Selector is re-executed
    • It compares the new value with the previous selected value (shallow compare by default)
  4. If the selected value changes → Component re-renders
  5. If value does NOT change → No re-render (performance optimization)

Example Code

import { useSelector } from "react-redux";

function Profile() {
  const username = useSelector(state => state.user.name);

  return <h3>Welcome, {username}</h3>;
}

Real-World Use Case

Imagine you have a dashboard with many widgets.
If each widget used the entire Redux store, everything would re-render on every update 😵

But with useSelector, each widget only re-renders when its specific data changes → huge performance improvement.

export const hasAccess = (state: Object): boolean => {
  return get(state, ['settings', 'admin']) === true;
};

This function is a Redux selector that uses Lodash’s get() to safely read deeply nested properties (settings.admin) from the Redux state.

It returns a boolean value (true or false) based on whether admin access is enabled.

Using it with useSelector:

const hasAdminAccess = useSelector(hasAccess);

This ensures your component automatically updates whenever state.settings.admin changes.

A selector is a pure function that takes the Redux state and returns the required piece of data.

Selectors improve:

BenefitExplanation
ReusabilitySame logic used everywhere
MaintainabilityState structure changes only affect selectors
Performance (with memoization)Can use reselect to avoid recomputing expensive values

📌 Example with nested access:

const selectUserEmail = (state) => state.user?.profile?.email;

📌 Memoized selector (advanced):

import { createSelector } from "reselect";

const selectUser = (state) => state.user;
const selectUserEmail = createSelector(
  [selectUser],
  (user) => user.profile.email
);

    useSelector subscribes to the Redux store and:

    1. Calls your selector whenever the state updates
    2. Compares new value with previous value using ===
    3. If changed → component re-renders
      If same → no re-render (optimization)

    📌 Example behavior:

    Previous valueNew valueRe-render?
    "test""test"❌ No
    "test""hello"✅ Yes
    {user:1}{user:1} (new object)✅ Yes (shallow compare fails)

    Performance Tip

    If selecting objects/arrays, use memoized selectors with createSelector to avoid unnecessary re-renders.

    How WhatsApp Notifications Work Internally — A System Design Perspective

    Have you ever wondered how WhatsApp notifies you instantly when someone sends a message — even when your app is closed? Let’s peel back the layers and look at how WhatsApp’s notification system actually works from a system design point of view.


    🧠 The Big Picture

    When you receive a new WhatsApp message like

    “Ravi: Hey Raju!”

    that notification travels through a complex, highly optimized system involving encryption, real-time messaging, and push infrastructure.

    Let’s break it down step by step 👇


    ⚙️ 1. Message Creation — The Journey Begins

    When Ravi sends a message to Raju:

    • The WhatsApp client on Ravi’s phone encrypts the message using end-to-end encryption (E2EE).
    • The encrypted payload is sent to WhatsApp’s Message Server through a persistent socket connection.

    At this point, the message is unreadable to anyone — even WhatsApp itself.


    📡 2. Message Routing — Finding the Recipient

    The Message Server receives Ravi’s encrypted message and determines that it needs to reach Raju’s device.

    • If Raju is online, the message is sent immediately via a persistent connection (using XMPP or WebSockets).
    • If Raju is offline, WhatsApp stores the encrypted message temporarily in its Storage Service until Raju reconnects.

    📬 3. Triggering a Notification — When the App Is Closed

    If Raju’s app is in the background or not connected, WhatsApp triggers a push notification.

    Here’s how it works:

    1. The Notification Service in WhatsApp’s backend detects that Raju is offline.
    2. It prepares a lightweight message payload — something like: { "to": "<Raju_Device_Token>", "notification": { "title": "WhatsApp", "body": "Ravi: Hey Raju!" }, "data": { "message_id": "abc123", "chat_id": "ravi_123" } }
    3. It sends this payload to Firebase Cloud Messaging (FCM) for Android or Apple Push Notification Service (APNS) for iPhone.

    ☁️ 4. Push Infrastructure — Google & Apple Step In

    Once WhatsApp sends the notification request:

    • FCM/APNS looks up the device token (a unique ID representing Raju’s phone).
    • They route the message through their global notification delivery networks.
    • Raju’s phone receives it instantly — even if the app isn’t open.

    This is possible because FCM and APNS maintain their own persistent channels with your device at the OS level.


    🔔 5. Notification Delivery on Device

    When Raju’s phone receives the notification:

    • The OS wakes up WhatsApp’s background receiver.
    • A notification appears on the lock screen or notification tray: “Ravi: Hey Raju!”

    When Raju taps it:

    • WhatsApp opens and establishes its secure socket connection to the server.
    • The actual encrypted message is fetched and decrypted locally using Raju’s private key.

    At this point, the two ticks ✅ (message delivered) appear on Ravi’s chat screen.
    When Raju reads it, WhatsApp sends a “read receipt” (blue ticks 💙) back.


    🔐 6. End-to-End Encryption (E2EE)

    One of WhatsApp’s strongest features is end-to-end encryption.

    • Messages are encrypted on Ravi’s device.
    • Stored in encrypted form on WhatsApp’s server (if needed).
    • Decrypted only on Raju’s device.

    Even WhatsApp’s servers can’t see the content — they only know that a message exists and who it’s meant for.


    🧩 7. Behind-the-Scenes Components

    Here’s what’s happening under the hood:

    ComponentRole
    Message ServiceHandles message routing between users
    Notification ServiceSends push notifications via FCM/APNS
    Encryption ServiceEncrypts and decrypts message payloads
    Storage ServiceStores encrypted messages for offline users
    Delivery TrackerTracks sent, delivered, and read states
    User Presence ServiceDetermines whether users are online or offline

    🧱 8. System Architecture Overview

    Conceptually, it looks like this:

    Ravi's Phone ──►(Encrypt Message) ──► Message Server ──► (Route + Store ) ──► Notification Service ──►(Push Notification) ──► FCM/APNS ──► Raju's Phone
    
    

    ⚡ 9. Why This Design Works So Well

    GoalHow WhatsApp Achieves It
    Real-time deliveryPersistent sockets (XMPP/WebSockets)
    Offline supportStored encrypted messages + push
    SecurityEnd-to-end encryption keys per user
    ScalabilityMicroservices + distributed queues
    Low latencyGlobal servers + efficient routing
    Battery efficiencyOS-managed push (via FCM/APNS)

    🚀 10. Key Takeaways for System Design Interviews

    If you’re designing a notification system like WhatsApp’s, remember these principles:

    1. Decouple message delivery and notification logic (use queues).
    2. Use push services (FCM/APNS) for offline or background delivery.
    3. Maintain persistent connections for real-time chat.
    4. Ensure reliability with retry, message persistence, and acknowledgment mechanisms.
    5. Design for privacy with end-to-end encryption and minimal metadata storage.

    🏁 Final Thoughts

    WhatsApp’s notification system is a perfect blend of real-time communication, security, and scalability.
    As a system architect, understanding how these layers interact — from event queues to encryption — is crucial for designing any large-scale, user-facing application.


    How to Generate a Release APK Using Gradle (Step by Step) – React Native

    When you build an Android app (native or React Native), you often need a Release APK — the file you can share with users or upload to the Play Store.
    Let’s understand how this works with just two commands.


    1️⃣ Move to the Android Folder

    cd android
    
    

    👉 Why?
    Every Android/React Native project has an android folder. Inside it, you’ll find the Gradle build system files.
    Gradle is the tool that actually builds your Android app.
    So before we run Gradle commands, we must go inside the android directory.


    2️⃣ Build the Release APK

    ./gradlew assembleRelease     # for Mac/Linux
    gradlew assembleRelease       # for Windows
    
    

    👉 What this does:

    • Runs the Gradle build system in release mode.
    • It compiles your Java/Kotlin code, bundles resources (images, layouts, etc.), and optimizes everything.
    • The result is an APK file that you can install on a device or publish.

    3️⃣ Where to Find the APK

    After the command finishes, you’ll see this path:

    android/app/build/outputs/apk/release/app-release.apk
    
    

    👉 Meaning:

    • android/ → the Android project folder
    • app/ → your app module
    • build/outputs/apk/release/ → Gradle puts the generated APKs here
    • app-release.apk → your final APK file

    📦 Debug vs Release APK

    • Debug APK:
    • Release APK:
      • Built using assembleRelease.
      • Signed with your own keystore (for Play Store upload).
      • Optimized (smaller & faster).

    🎯 Purpose of These Commands

    • cd android → Go inside the Android project where Gradle is located.
    • ./gradlew assembleRelease → Tell Gradle to build a release-ready APK.
    • android/app/build/outputs/apk/release/app-release.apk → Location of your generated APK.

    With this APK:
    ✅ You can test the final production build on a real device.
    ✅ You can upload it to the Google Play Store after signing it with your keystore.


    🎓 Final Takeaway

    • cd android → enter Android folder
    • ./gradlew assembleRelease → build release APK
    • app-release.apk → your final app file, ready to be shared or published

    👉 Think of it like baking a cake:

    • cd android = entering the kitchen
    • ./gradlew assembleRelease = starting the baking process
    • app-release.apk = the finished cake 🎂

    Controlled vs Uncontrolled Components in React (Beginner Friendly)

    When you start learning React, one of the first confusing topics you’ll face is the difference between Controlled and Uncontrolled Components. Don’t worry — by the end of this post, you’ll understand this clearly with simple examples.


    🎯 What Does It Mean?

    In simple words:

    • Controlled Component → React is in charge of the input’s value.
    • Uncontrolled Component → The browser (DOM) is in charge of the input’s value.

    Think of it like this:

    • In Controlled Components, React acts like a teacher, checking every word you write in your notebook.
    • In Uncontrolled Components, React acts like a teacher who lets you write freely and only checks your notebook at the end.

    📝 Controlled Components

    In a controlled component, the form input is linked to React state. That means React always knows what’s inside the input, and it updates automatically when you type.

    Example: Controlled Input

    import React, { useState } from "react";
    
    function ControlledForm() {
      const [name, setName] = useState(""); // React state
    
      const handleSubmit = (e) => {
        e.preventDefault();
        alert("Submitted Name: " + name);
      };
    
      return (
        <form onSubmit={handleSubmit}>
          <input
            type="text"
            value={name} // value comes from React state
            onChange={(e) => setName(e.target.value)} // update state
            placeholder="Enter your name"
          />
          <button type="submit">Submit</button>
        </form>
      );
    }
    
    export default ControlledForm;
    
    

    👉 Here:

    • The input value is always controlled by React.
    • When you type, React updates the state and then shows the updated value back in the input.
    • React is the single source of truth.

    📝 Uncontrolled Components

    In an uncontrolled component, the input manages its own value just like in plain HTML. You don’t use state, instead you use a ref to get the value when needed.

    Example: Uncontrolled Input

    import React, { useRef } from "react";
    
    function UncontrolledForm() {
      const nameRef = useRef(); // reference to input
    
      const handleSubmit = (e) => {
        e.preventDefault();
        alert("Submitted Name: " + nameRef.current.value);
      };
    
      return (
        <form onSubmit={handleSubmit}>
          <input
            type="text"
            ref={nameRef} // React does not control this input
            placeholder="Enter your name"
          />
          <button type="submit">Submit</button>
        </form>
      );
    }
    
    export default UncontrolledForm;
    
    

    👉 Here:

    • The browser keeps track of what you type.
    • React doesn’t know the input value until you read it with ref.
    • DOM is the source of truth.

    🔑 Key Differences

    FeatureControlledUncontrolled
    Value managed byReact stateDOM (browser)
    How to read valueFrom stateFrom ref.current.value
    React controlHigh (can validate instantly)Low
    Use caseValidation, dynamic forms, live feedbackSimple forms, quick data grab

    🚀 When Should You Use Which?

    • ✅ Use Controlled Components when you need:
      • Form validation (e.g., check if email is valid while typing)
      • Live updates (e.g., show typed text somewhere else instantly)
      • Complex or large forms
    • ✅ Use Uncontrolled Components when you need:
      • Simple, one-time form submissions
      • Quick prototypes
      • Minimal React state management

    🎓 Final Takeaway

    • Controlled → React is the boss. It decides what’s in the input.
    • Uncontrolled → Browser is the boss. React just asks for the value when needed.

    👉 As a beginner, it’s usually best to start with Controlled Components because they give you more power and flexibility. But knowing Uncontrolled Components will help you understand how React works with the DOM.


    Top 20 Node.js Interview Questions & Answers [2025 Updated]

    1. What is Node.js?

    • Concept: Node.js is a JavaScript runtime built on Chrome’s V8 engine, enabling server-side JavaScript execution.
    • Example:
    console.log("Hello from Node.js!");
    
    
    • Real Use Case: Powering backend servers for apps like Netflix, PayPal, or LinkedIn.

    2. What is the Event Loop in Node.js?

    • Concept: The event loop handles asynchronous operations, allowing non-blocking I/O.
    • Example:
    setTimeout(() => console.log("Executed later"), 0);
    console.log("Executed first");
    
    
    • Real Use Case: Efficient handling of thousands of requests in chat apps like WhatsApp Web.

    3. What are Streams in Node.js?

    • Concept: Streams let you read/write data piece by piece instead of loading it all at once.
    • Example:
    const fs = require('fs');
    fs.createReadStream('file.txt').pipe(process.stdout);
    
    
    • Real Use Case: Video/audio streaming platforms (YouTube, Spotify).

    4. Difference between require and import

    • Concept: require is CommonJS; import is ES Module syntax.
    • Example:
    // CommonJS
    const fs = require('fs');
    
    // ES Module
    import fs from 'fs';
    
    
    • Real Use Case: require for legacy Node apps, import for modern apps with ES Modules.

    5. What is Middleware in Node.js (Express)?

    • Concept: Functions that execute during request/response lifecycle.
    • Example:
    app.use((req, res, next) => {
      console.log("Request Time:", Date.now());
      next();
    });
    
    
    • Real Use Case: Logging, authentication, error handling in Express apps.

    6. What are Promises & Async/Await?

    • Concept: Handle asynchronous code more cleanly than callbacks.
    • Example:
    const fetchData = async () => {
      let res = await fetch("https://api.github.com/users");
      console.log(await res.json());
    };
    
    
    • Real Use Case: API requests in e-commerce checkout systems.

    7. What is the difference between Process & Thread in Node.js?

    • Concept: Process = instance of program, Thread = unit of execution inside process. Node.js is single-threaded with background worker threads.
    • Example: Running one Node process with multiple requests handled asynchronously.
    • Real Use Case: Scaling microservices with cluster module.

    8. Explain Node.js Clustering

    • Concept: Allows running multiple Node.js processes to utilize multi-core CPUs.
    • Example:
    const cluster = require('cluster');
    if (cluster.isMaster) {
      cluster.fork();
    } else {
      console.log("Worker process running");
    }
    
    
    • Real Use Case: Improving throughput in high-traffic apps (Uber, Paytm).

    9. What is process.nextTick()?

    • Concept: Executes callback after the current operation, before event loop continues.
    • Example:
    process.nextTick(() => console.log("Next Tick executed"));
    console.log("Main code");
    
    
    • Real Use Case: Deferring execution in async libraries like Mongoose.

    10. What is an EventEmitter?

    • Concept: A core module for event-driven programming.
    • Example:
    const EventEmitter = require('events');
    const emitter = new EventEmitter();
    emitter.on('start', () => console.log('Started!'));
    emitter.emit('start');
    
    
    • Real Use Case: Notification systems, chat events.

    11. What are Worker Threads in Node.js?

    • Concept: Allow running JavaScript in parallel threads.
    • Example:
    const { Worker } = require('worker_threads');
    new Worker('./worker.js');
    
    
    • Real Use Case: Heavy CPU tasks like video compression.

    12. Difference between Synchronous & Asynchronous code

    • Concept: Sync blocks execution, async allows parallel tasks.
    • Example:
    // Sync
    let data = fs.readFileSync('file.txt');
    
    // Async
    fs.readFile('file.txt', (err, data) => console.log(data));
    
    
    • Real Use Case: Async is critical for APIs and file systems.

    13. What is JWT and how is it used in Node.js?

    • Concept: JSON Web Token for authentication.
    • Example:
    jwt.sign({ userId: 1 }, "secretKey");
    
    
    • Real Use Case: Secure login in apps like Facebook/Google sign-in.

    14. What is the difference between fs.readFile and fs.createReadStream?

    • Concept: readFile loads entire file, createReadStream streams it in chunks.
    • Example:
    fs.readFile('big.txt', ...); 
    fs.createReadStream('big.txt').pipe(process.stdout);
    
    
    • Real Use Case: Large file handling (logs, videos).

    15. What is Nodemon?

    • Concept: A tool that auto-restarts Node.js server on file changes.
    • Example:
    npx nodemon app.js
    
    
    • Real Use Case: Developer productivity during backend coding.

    16. What are Environment Variables in Node.js?

    • Concept: Variables stored outside the code for configs.
    • Example:
    process.env.PORT || 3000;
    
    
    • Real Use Case: Storing API keys, DB credentials.

    17. Explain CORS in Node.js

    • Concept: Cross-Origin Resource Sharing allows restricted resources to be accessed from another domain.
    • Example:
    const cors = require('cors');
    app.use(cors());
    
    
    • Real Use Case: Allowing frontend (React/Angular) to call backend API.

    18. What is the difference between Monolithic & Microservices in Node.js?

    • Concept:
      • Monolithic: Single large codebase.
      • Microservices: Independent services communicating via APIs.
    • Example: Splitting user service, product service, payment service.
    • Real Use Case: Netflix migrated from monolithic to microservices using Node.js.

    19. What is Rate Limiting in Node.js?

    • Concept: Restrict number of requests to avoid abuse.
    • Example:
    const rateLimit = require("express-rate-limit");
    app.use(rateLimit({ windowMs: 60*1000, max: 5 }));
    
    
    • Real Use Case: Preventing brute-force login attacks.

    20. How does Node.js handle child processes?

    • Concept: Allows spawning new processes.
    • Example:
    const { exec } = require('child_process');
    exec('ls', (err, stdout) => console.log(stdout));
    
    
    • Real Use Case: Running background tasks like sending emails.