Skip to content

Instantly share code, notes, and snippets.

@ronjunevaldoz
Last active March 19, 2026 05:05
Show Gist options
  • Select an option

  • Save ronjunevaldoz/ac5e5e84e89e287c17fcd2b2d75c7a75 to your computer and use it in GitHub Desktop.

Select an option

Save ronjunevaldoz/ac5e5e84e89e287c17fcd2b2d75c7a75 to your computer and use it in GitHub Desktop.

🚀 MERN Cheatsheet Reviewer (Extended)


📘 Frontend (FE)

🔹 ReactJS Hooks

Hook Purpose Example
useState Manage local state const [count, setCount] = useState(0);
useEffect Side effects (API calls, subs) useEffect(()=>{ fetchData(); }, [dep]);
useContext Access context values const theme = useContext(ThemeContext);
useReducer Complex state logic useReducer(reducer, initialState);
useRef Persist values / DOM refs const inputRef = useRef();
useMemo Memoize expensive computations useMemo(()=>calc(items), [items]);
useCallback Memoize functions useCallback(()=>doSomething(), []);

🔹 Redux Keywords

  • Store → Centralized state container
  • Reducer → Pure function (state, action) => newState
  • Action → Plain object { type, payload }
  • Dispatch → Sends actions to reducers
  • Selector → Extracts data from store
  • Middleware → Intercepts actions (e.g., Thunk, Saga)
  • Provider → Makes store available to React components

🔹 Redux Toolkit (RTK) - Modern Standard

RTK simplifies Redux by removing boilerplate. It uses createSlice to combine actions and reducers.

1. Create a Slice (counterSlice.js)

import { createSlice } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    increment: (state) => {
      // RTK uses Immer, so you can "mutate" state safely
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload;
    },
  },
});

export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;

2. Configure Store (store.js)

import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

🔹 Redux State Management (Snippet)

Store Setup

import { createStore } from 'redux';

// Reducer
const counterReducer = (state = { count: 0 }, action) => {
  switch(action.type) {
    case 'INCREMENT': return { count: state.count + 1 };
    case 'DECREMENT': return { count: state.count - 1 };
    default: return state;
  }
};

// Store
const store = createStore(counterReducer);

// Dispatch
store.dispatch({ type: 'INCREMENT' });
console.log(store.getState()); // { count: 1 }

With React

import { Provider, useSelector, useDispatch } from 'react-redux';

function Counter() {
  const count = useSelector(state => state.count);
  const dispatch = useDispatch();

  return (
    <div>
      <p>{count}</p>
      <button onClick={()=>dispatch({ type: 'INCREMENT' })}>+</button>
      <button onClick={()=>dispatch({ type: 'DECREMENT' })}>-</button>
    </div>
  );
}

🔹 JavaScript Advanced Syntax

  • Destructuringconst { name, age } = person;
  • Spread Operator → Copy + modify arrays/objects
  • Optional Chaininguser?.profile?.email
  • Nullish Coalescingconst val = input ?? "default";
  • Async/Awaitconst data = await fetchData();
  • Template Literals`Hello, ${name}!`
  • Strict vs Loose Equality=== vs ==
  • Truthy/Falsyfalse, 0, "", null, undefined, NaN vs everything else

🟡 JavaScript Fundamentals: Scope & Hoisting

🔹 var vs let vs const

The way you declare variables affects their scope, mutability, and how they behave during the execution phase.

Feature var let const
Scope Function Scope Block Scope { } Block Scope { }
Hoisting Hoisted (initialized as undefined) Hoisted (Temporal Dead Zone) Hoisted (Temporal Dead Zone)
Reassignable ✅ Yes ✅ Yes ❌ No
Redeclarable ✅ Yes ❌ No ❌ No

Examples:

// Block Scope Example
if (true) {
  var functionScoped = "I am visible outside!";
  let blockScoped = "I am hidden outside!";
}
console.log(functionScoped); // "I am visible outside!"
console.log(blockScoped);    // ReferenceError

// Const Mutability (Objects/Arrays)
const user = { name: "Alice" };
user.name = "Bob"; // ✅ Allowed (mutating property)
user = {};         // ❌ TypeError (reassigning variable)

📗 Backend (BE)

🔹 NodeJS Endpoints (Express)

Event-driven architecture: Node.js is built around an event loop that listens for events (like incoming requests, timers, or file reads) and dispatches callbacks when they’re ready.

Single-threaded execution: Your JavaScript runs on one main thread, but Node.js can still handle thousands of concurrent connections thanks to non-blocking I/O.

libuv: This C library powers Node’s event loop and provides a thread pool for heavy tasks (file system, crypto, DNS). So while JS is single-threaded, Node can offload work to background threads.

const express = require('express');
const app = express();
app.use(express.json());

app.get('/items', (req,res)=> res.send("GET items"));
app.post('/items', (req,res)=> res.send("POST item"));
app.put('/items/:id', (req,res)=> res.send("PUT item " + req.params.id));

app.listen(3000, ()=> console.log("Server running"));

🔹 Mongoose Query Syntax (Extended)

Basic Queries

  • Model.find({}); → Find all
  • Model.findOne({ name: "John" }); → Find one
  • Model.findById(id); → Find by ID
  • new Model({ field: val }).save(); → Insert
  • Model.updateOne({ _id:id }, { $set:{ field:val } }); → Update
  • Model.deleteOne({ _id:id }); → Delete

Advanced Queries

  • ProjectionModel.find({}, 'name age');
  • SortingModel.find().sort({ age: -1 });
  • PaginationModel.find().skip(10).limit(5);
  • Population (relations)Model.find().populate('author');
  • Aggregation
    Model.aggregate([
      { $match: { status: "active" } },
      { $group: { _id: "$category", total: { $sum: 1 } } }
    ]);
  • Schema Validation
    const userSchema = new mongoose.Schema({
      email: { type: String, required: true, unique: true },
      age: { type: Number, min: 18 }
    });
  • IndexesuserSchema.index({ email: 1 });
  • Middleware (Hooks)userSchema.pre('save', function(next){ ... });
  • VirtualsuserSchema.virtual('fullName').get(function(){ return this.firstName + " " + this.lastName; });

🔹 Package.json Dependencies (Extended)

Dependencies

  • Installed with npm install <package>
  • Required in production runtime.
  • Examples:
    • "express": "^4.18.2"
    • "mongoose": "^7.0.0"

DevDependencies

  • Installed with npm install <package> --save-dev
  • Needed only in development/testing/build.
  • Examples:
    • "nodemon": "^3.0.1" (auto-restart server)
    • "jest": "^29.0.0" (testing framework)
    • "eslint": "^8.0.0" (linting)

Other Fields

  • scripts → Custom commands
  • peerDependencies → Packages expected to be installed by the consumer (e.g., React libraries).
  • optionalDependencies → Not required; app runs even if missing.
  • bundledDependencies → Included when publishing a package.
  • engines → Specify Node.js version compatibility.
  • config → Custom configuration values for scripts.

Key Differences

Aspect dependencies devDependencies
Purpose Runtime use Development only
Installed in Prod ✅ Yes ❌ No
Examples express, mongoose nodemon, jest, eslint
Command npm install npm install --save-dev

####🔹 Testing with Jest & React Testing Library

Testing a Redux Slice

import counterReducer, { increment } from './counterSlice';

test('should handle initial state', () => {
  expect(counterReducer(undefined, { type: 'unknown' })).toEqual({ value: 0 });
});

test('should handle increment', () => {
  const previousState = { value: 10 };
  expect(counterReducer(previousState, increment())).toEqual({ value: 11 });
});

Testing a Component

import { render, screen, fireEvent } from '@testing-library/react';
import Counter from './Counter';

test('increments counter on button click', () => {
  render(<Counter />);
  const button = screen.getByText('+');
  fireEvent.click(button);
  expect(screen.getByText('1')).toBeInTheDocument();
});

🧪 Jest Common Functions & Matchers

Jest is the industry standard for testing JavaScript. Understanding its lifecycle and matchers is key to writing reliable unit tests.

🔹 Lifecycle Hooks

Used to set up or tear down environments before/after tests (e.g., clearing a database or resetting a mock).

Function Description
beforeAll() Runs once before all tests in a file/describe block
beforeEach() Runs before every single test
afterEach() Runs after every single test
afterAll() Runs once after all tests are finished

🔹 Common Matchers

Matchers allow you to validate values in different ways.

1. Equality & Truthiness

test('basic matchers', () => {
  expect(2 + 2).toBe(4);                 // Exact equality (Object.is)
  expect({a: 1}).toEqual({a: 1});       // Deep equality (objects/arrays)
  expect(n).toBeNull();                 // Only matches null
  expect(n).toBeDefined();              // Opposite of undefined
  expect(n).toBeTruthy();               // Matches anything an if-statement treats as true
});

⚡ Rapid-Fire Interview Q&A

  • Redux vs Context API? → Redux is more scalable with middleware and dev tools; Context is simpler but not ideal for complex state.
  • Difference between findOne and findById in Mongoose?findOne matches any field; findById specifically matches _id.
  • When to use Aggregation in Mongoose? → For analytics, grouping, and complex queries.
  • What does populate do? → Replaces referenced ObjectId with actual document data.
  • Why use devDependencies? → To keep production lean; dev tools aren’t needed in runtime.
  • What are peerDependencies? → Packages expected to be installed by the consumer (e.g., React version for a library).
  • Difference between useEffect and useLayoutEffect?useEffect runs after paint; useLayoutEffect runs before paint (blocking).
  • Why use middleware in Redux? → To handle async logic and side effects.
  • Difference between npm install and npm install --save-dev? → First adds to dependencies, second adds to devDependencies.
  • What is the purpose of indexes in Mongoose? → Speed up queries by optimizing lookups.

🎯 Quick Reminders

  • Redux: Store → Reducer → Action → Dispatch → Selector → Middleware → UI.
  • Mongoose: Populate for relationships, Aggregate for analytics, Indexes for performance, Middleware for lifecycle hooks.
  • Package.json: Dependencies for runtime, devDependencies for dev tools, peerDependencies for shared libs.

Scalable Service Patterns

Horizontal Scaling

  • Run multiple instances across servers/containers
  • Use load balancers (NGINX, HAProxy, AWS ELB, Kubernetes)
  • Distributes traffic, avoids single-node bottlenecks

Clustering

  • Pattern: Use Node.js cluster module to spawn workers across CPU cores
  • Example:
    const cluster = require('cluster');
    const http = require('http');
    const os = require('os');
    
    if (cluster.isMaster) {
      os.cpus().forEach(() => cluster.fork());
    } else {
      http.createServer((req, res) => {
        res.end("Hello from worker " + process.pid);
      }).listen(3000);
    }
  • Benefit: Utilizes all cores on a single machine.

Microservices

  • Pattern: Break a monolithic app into smaller services (auth, payments, orders).
  • Tools: Docker, Kubernetes, message brokers (RabbitMQ, Kafka).
  • Benefit: Independent scaling, easier maintenance, fault isolation.

Event-Driven & Message Queues

  • Pattern: Use queues to decouple producers and consumers.
  • Tools: RabbitMQ, Kafka, Redis Pub/Sub.
  • Benefit: Smooths out spikes in traffic, improves resilience.

Caching

  • Pattern: Store frequently accessed data in memory.
  • Tools: Redis, Memcached.
  • Benefit: Reduces database load, speeds up responses.

Database Scaling

  • Pattern: Use replication, sharding, or read/write splitting.
  • Tools: MongoDB sharding, PostgreSQL replication.
  • Benefit: Handles large datasets and high query volumes.

API Gateway & Reverse Proxy

  • Pattern: Central entry point for routing, authentication, rate limiting.
  • Tools: Kong, NGINX, AWS API Gateway.
  • Benefit: Simplifies client interaction, adds security and monitoring.

⚖️ Choosing the Right Pattern

  • High traffic, simple app → Clustering + caching.
  • Complex domain, multiple teams → Microservices + API Gateway.
  • Spiky workloads → Message queues + autoscaling.
  • Data-heavy apps → Database sharding + caching.

Resilient API Designs

Fault Tolerance

  • Use retries with exponential backoff
  • Implement circuit breakers (e.g., with libraries like opossum)
  • Gracefully degrade when dependencies fail

Rate Limiting & Throttling

  • Protect APIs from abuse and overload
  • Tools: NGINX, API Gateway, Redis-based counters
  • Strategies: fixed window, sliding window, token bucket

Caching & Idempotency

  • Cache frequent responses (Redis, CDN)
  • Ensure idempotent endpoints (e.g., POST with unique request IDs)
  • Prevent duplicate processing during retries

Timeout & Fallbacks

  • Set timeouts for external calls
  • Provide fallback responses or cached data
  • Avoid hanging requests that block resources

Monitoring & Observability

  • Collect metrics (latency, error rates, throughput)
  • Use distributed tracing (Jaeger, Zipkin, OpenTelemetry)
  • Log structured events for debugging

Security & Validation

  • Validate inputs to prevent injection attacks
  • Use authentication & authorization (OAuth2, JWT)
  • Apply HTTPS everywhere

Versioning & Compatibility

  • Support multiple API versions (v1, v2)
  • Use semantic versioning for breaking changes
  • Provide backward compatibility when possible

Graceful Degradation

  • Return partial data if full response unavailable
  • Inform clients of reduced functionality
  • Keep core features available under stress

Resilience Patterns

  • Bulkhead: isolate resources to prevent cascading failures
  • Circuit Breaker: stop calls to failing services temporarily
  • Retry with Backoff: retry failed requests intelligently
  • Fail Fast: quickly reject requests when system is overloaded

Quick Checklist

  • ✅ Retries with backoff
  • ✅ Circuit breakers
  • ✅ Rate limiting
  • ✅ Idempotency
  • ✅ Timeouts & fallbacks
  • ✅ Monitoring & tracing
  • ✅ Secure endpoints
  • ✅ Graceful degradation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment