React Tutorial for Professionals

React Tutorial for Professionals: Modern Hooks, Redux, Routing, Testing

βœ… What is React?

React is a JavaScript library developed by Facebook for building user interfaces, particularly single-page applications (SPAs). It’s component-based, declarative, and enables fast UI updates.

🧱 Core Concepts in React

1. Components

  • Function components – the modern way.
  • Class components – legacy but still found in codebases.

2. JSX

JSX is a syntax extension for JavaScript that looks like HTML and is used to describe the UI.

const Hello = () => <h1>Hello World</h1>;

3. Props (Properties)

Used to pass data from parent to child components.

const Welcome = ({ name }) => <h1>Hi {name}</h1>;

4. State

Holds local component data that can change over time.

  • Functional: useState
  • Class: this.state

🎯 Functional vs Class Components

FeatureClass ComponentFunctional Component
Syntaxextends React.ComponentPlain JavaScript functions
State Managementthis.state, this.setState()useState()
Lifecycle MethodscomponentDidMount, etc.useEffect()
ReadabilityVerboseConcise
PerformanceSlightly slower (more boilerplate)Faster and optimized with Hooks
Modern Best Practice❌ Legacyβœ… Recommended
Access to HooksβŒβœ…

🧠 Functional Component Example

import React, { useState } from "react";

function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<h2>{count}</h2>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}

πŸ›οΈ Class Component Example

import React from "react";

class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}

increment = () => {
this.setState({ count: this.state.count + 1 });
};

render() {
return (
<div>
<h2>{this.state.count}</h2>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}

πŸš€ Folder Structure (Best Practice)

src/
β”‚
β”œβ”€β”€ components/
β”‚ └── Button.jsx
β”œβ”€β”€ pages/
β”‚ └── Home.jsx
β”œβ”€β”€ hooks/
β”‚ └── useFetch.js
β”œβ”€β”€ context/
β”‚ └── AuthContext.js
β”œβ”€β”€ App.jsx
β”œβ”€β”€ index.js

πŸ” Real DOM vs Virtual DOM in React

FeatureReal DOMVirtual DOM
DefinitionActual DOM rendered by browserIn-memory JS object representation
Update SpeedSlowFast (via diffing and batching)
EfficiencyLow (re-renders whole tree)High (only updates changes)
Re-renderingFull tree reflowSelective updates
Use in ReactBrowser managedReact managed
Example FrameworksjQuery, Vanilla JSReact, Vue, Angular (conceptually)

βœ… Feature of React

Sure! Here are the key features of React in short:

  1. JSX – JavaScript syntax extension to write HTML-like code.
  2. Components – Reusable, modular UI blocks.
  3. Virtual DOM – Efficient UI updates via diffing.
  4. One-way Data Binding – Data flows from parent to child.
  5. Hooks – Use state and lifecycle in functional components.
  6. Declarative UI – Describe what the UI should look like.
  7. Unidirectional Flow – Predictable data handling.
  8. React Native Support – Build mobile apps using React.
  9. Strong Ecosystem – React Router, Redux, etc.
  10. Community & Tooling – Large support and dev tool

βœ… React Limitation

Here are the limitations of React (short and clear):

  1. JSX Complexity – JSX can be confusing for beginners.
  2. Only UI Layer – React handles view only, needs other libraries for routing, state, etc.
  3. Fast Updates Can Break Things – Frequent changes require constant learning.
  4. SEO Limitations – Without SSR (like Next.js), React apps can struggle with SEO.
  5. Boilerplate Code – Setting up large apps needs config and structure.
  6. Learning Curve – Advanced concepts (hooks, context, refs) can be complex.
  7. Poor Documentation for Ecosystem Tools – Some third-party libraries are under-documented.
  8. Too Many Choices – State management, routing, etc., have many competing options.

βœ… JSX (JavaScript XML)

JSX is a syntax extension for JavaScript used in React to describe UI elements in a way that looks like HTML.

πŸ”Ή Example:

const element = <h1>Hello, world!</h1>;

This looks like HTML but is actually converted to JavaScript under the hood using Babel:

const element = React.createElement("h1", null, "Hello, world!");

🧠 Virtual DOM – Explained Simply

The Virtual DOM (VDOM) is a lightweight JavaScript copy of the Real DOM used by React to efficiently update the UI.

πŸ”Ή How It Works:

  1. UI is built in Virtual DOM.
  2. When state/props change, a new VDOM is created.
  3. React compares (diffs) old vs new VDOM.
  4. Only the changed parts are updated in the Real DOM.

βœ… Benefits:

  • Faster UI updates
  • Improved performance
  • Efficient rendering
  • Better user experience

❓ Why Doesn’t the Browser Read JSX?

Because JSX is not valid JavaScript or HTML β€” it’s a syntax extension that browsers don’t understand natively.

Before JSX runs in the browser, tools like Babel convert it into pure JavaScript:

πŸ” React ES6 vs ES5 – Key Differences

React code can be written using ES5 (older JavaScript) or ES6+ (modern JavaScript with new features). Modern React prefers ES6+ due to cleaner syntax and better support for components.

πŸ†š Comparison Table: ES5 vs ES6 in React

FeatureES5 (Old Way)ES6 (Modern Way)
Component CreationReact.createClass()class extends React.Component
Variable Declarationvarlet / const
Function Declarationfunction () {}Arrow function () => {}
Binding thisManual bind in constructorArrow functions auto-bind this
Props Accessthis.props.namethis.props.name (same)
State InitializationInside getInitialState()Inside constructor or hooks
Importsvar React = require('react')import React from 'react'
Exportmodule.exports = Componentexport default Component

πŸ” React vs Angular – Quick Comparison

FeatureReactAngular
TypeLibrary for UIFull-fledged framework
LanguageJavaScript + JSXTypeScript
ArchitectureView (V in MVC)MVC/MVVM
Learning CurveEasy to moderateSteeper (more concepts)
DOMVirtual DOMReal DOM with change detection
Data BindingOne-wayTwo-way and one-way
Component-Basedβœ… Yesβœ… Yes
State ManagementExternal (Redux, Context, etc.)Built-in services & RxJS
RoutingExternal (React Router)Built-in
PerformanceFast with VDOMSlightly heavier but optimized
Mobile SupportReact NativeAngular with Ionic or NativeScript
Community & EcosystemHuge community, flexible choicesStrong, opinionated ecosystem
Use CaseSPAs, UIs, lightweight appsEnterprise-level, large-scale apps

βœ… Choose React: For flexibility, lightweight UIs, and faster development
βœ… Choose Angular: For structured enterprise apps with built-in tooling

πŸ” render() and React.Fragment in React

🧱 render() Method

  • Used only in class components.
  • It defines what to show on the screen.

βœ… Syntax:

class MyComponent extends React.Component {
render() {
return <h1>Hello, world!</h1>;
}
}

πŸ”Ή Key Points:

  • Required in every class component.
  • Should return only one parent element (can be a div or Fragment).

🧩 React.Fragment

  • Used to group multiple elements without adding extra DOM nodes.
  • Helps avoid unnecessary <div> wrappers.

βœ… Syntax:

return (
<React.Fragment>
<h1>Title</h1>
<p>Description</p>
</React.Fragment>
);

βœ… Shorter version using empty tags:

return (
<>
<h1>Title</h1>
<p>Description</p>
</>
);

πŸ” Props vs State in React

FeaturePropsState
DefinitionData passed from parent to childLocal data managed inside a component
MutabilityImmutable (read-only)Mutable (can change with setState/useState)
Use CaseFor configuration/inputFor tracking data that changes over time
Who Controls ItParent componentComponent itself
AccessibilityAvailable via this.props or propsAvailable via this.state or [state, setState]
Lifecycle ImpactDoes not trigger re-renders by itselfTriggers re-render when updated
Functional UsePassed as arguments in function componentsManaged using useState() in function components

βœ… Example of Props:

function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}

βœ… Example of State:

function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}

🧠 Summary

Use state to manage dynamic internal data of a component.
Use props to pass data into a component.

πŸ”„ Updating State in Class Components using this.setState()

In React class components, you never modify this.state directly. Instead, use this.setState() to update the component’s state and trigger a re-render.

βœ… Syntax:

this.setState({ key: newValue });

🧠 Example:

class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}

increment = () => {
this.setState({ count: this.state.count + 1 });
};

render() {
return (
<div>
<h2>{this.state.count}</h2>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}

⚠️ Important Notes:

  1. Asynchronous: this.setState() is async. Don’t rely on this.state right after setting it.
  2. Using Previous State: Use a function for safe updates based on previous state.
this.setState(prevState => ({
count: prevState.count + 1
}));
  1. Triggers Re-render: Every setState() call updates the component and re-renders the UI.

πŸ” What does super(props); mean in React?

πŸ”Ή Why is it used?

  1. super(props) calls the parent constructor (React.Component) and passes the props to it.
  2. It allows you to use this.props inside the constructor.

Without calling super(props), this is undefined, and accessing this.props will throw an error.

πŸ” Arrow Functions in React

Arrow functions (=>) are widely used in React for cleaner and more concise code, especially in event handlers, functional components, and class methods.

βœ… Basic Syntax:

const add = (a, b) => a + b;

βœ… 1. Arrow Functions in Functional Components

const Hello = () => {
return <h1>Hello World</h1>;
};

Or shorter:

const Hello = () => <h1>Hello World</h1>;

βœ… 2. Arrow Functions as Event Handlers (Class Components)

class Button extends React.Component {
state = { count: 0 };

handleClick = () => {
this.setState({ count: this.state.count + 1 });
};

render() {
return <button onClick={this.handleClick}>Click {this.state.count}</button>;
}
}

πŸ”Ή Why use arrow functions here?

  • Automatically bind this
  • No need for manual binding in constructor

βœ… 3. Arrow Functions Inline

<button onClick={() => console.log("Clicked")}>Click me</button>

⚠️ Note:

  • Avoid using inline arrow functions in performance-critical areas (can cause re-renders).

🧠 Key Benefits:

FeatureBenefit
this bindingNo need for manual binding
Concise syntaxCleaner and shorter function syntax
Best with hooksUsed extensively in modern React

πŸ” Stateful vs Stateless Components in React – Quick Comparison

FeatureStateful ComponentStateless Component
Holds Stateβœ… Yes (manages its own state)❌ No state (pure UI rendering)
Re-rendersBased on state or props changesBased on props only
TypeClass or functional with useState()Functional (no state/hooks)
Use CaseDynamic components (e.g., form, counter)UI-only components (e.g., header, label)
Lifecycle MethodsAvailable in class componentsNot applicable
ComplexityMore complexSimple and reusable

βœ… Stateful Component Example (with useState):

function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}

βœ… Stateless Component Example:

function Greeting(props) {
return <h1>Hello, {props.name}</h1>;
}

πŸ” Different Phases of a React Component’s Lifecycle (Class-Based)

React class components go through three main lifecycle phases:

πŸŒ€ 1. Mounting Phase

Component is created and inserted into the DOM.

πŸ”§ Lifecycle Methods:

MethodPurpose
constructor()Initialize state and bind methods
static getDerivedStateFromProps()Sync state from props (rarely used)
render()Returns JSX to render the UI
componentDidMount()Called once after component is rendered

πŸ”„ 2. Updating Phase

Triggered when props or state changes.

πŸ”§ Lifecycle Methods:

MethodPurpose
static getDerivedStateFromProps()Called on update too
shouldComponentUpdate()Decide whether to re-render or not
render()Re-renders UI
getSnapshotBeforeUpdate()Captures info (like scroll) before update
componentDidUpdate()Invoked after DOM updates

❌ 3. Unmounting Phase

Component is removed from the DOM.

πŸ”§ Lifecycle Method:

MethodPurpose
componentWillUnmount()Cleanup: remove timers, listeners, etc.

πŸ” Optional: Error Handling Phase

React also includes error handling lifecycle methods.

MethodPurpose
componentDidCatch()Catch errors in child components
static getDerivedStateFromError()Update UI when an error occurs

βœ… Modern Functional Components Lifecycle (with Hooks)

PhaseHook
MountuseEffect(() => { ... }, [])
UpdateuseEffect(() => { ... }, [deps])
UnmountuseEffect(() => { return () => {...} }, [])

πŸ”’ Order of React Lifecycle Methods (Class Components)

Here is the exact order in which React class component lifecycle methods are called:

πŸŒ€ 1. Mounting Phase (Component Creation)

StepMethodPurpose
1️⃣constructor()Initialize state and bindings
2️⃣static getDerivedStateFromProps()Sync state with props (rare use)
3️⃣render()Return JSX
4️⃣componentDidMount()Perform side-effects (API calls, etc.)

πŸ”„ 2. Updating Phase (State or Props Change)

Triggered by setState() or receiving new props.

StepMethodPurpose
1️⃣static getDerivedStateFromProps()Again (if needed)
2️⃣shouldComponentUpdate()Decide whether to re-render
3️⃣render()Re-render UI
4️⃣getSnapshotBeforeUpdate()Capture info before DOM changes
5️⃣componentDidUpdate()Reacts to the update

❌ 3. Unmounting Phase (Component Removal)

StepMethodPurpose
1️⃣componentWillUnmount()Cleanup (timers, subscriptions, etc.)

⚠️ 4. Error Handling Phase (If Error Occurs)

StepMethodPurpose
1️⃣static getDerivedStateFromError()Set fallback UI
2️⃣componentDidCatch()Log or handle error details


βœ… Full Example: Class Component Lifecycle

import React from "react";

class LifecycleDemo extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
console.log("1️⃣ constructor");
}

static getDerivedStateFromProps(props, state) {
console.log("2️⃣ getDerivedStateFromProps");
return null; // No state update from props
}

componentDidMount() {
console.log("4️⃣ componentDidMount");
}

shouldComponentUpdate(nextProps, nextState) {
console.log("5️⃣ shouldComponentUpdate");
return true; // allow update
}

getSnapshotBeforeUpdate(prevProps, prevState) {
console.log("6️⃣ getSnapshotBeforeUpdate");
return null;
}

componentDidUpdate(prevProps, prevState, snapshot) {
console.log("7️⃣ componentDidUpdate");
}

componentWillUnmount() {
console.log("8️⃣ componentWillUnmount");
}

increment = () => {
this.setState({ count: this.state.count + 1 });
};

render() {
console.log("3️⃣ render");
return (
<div>
<h2>Count: {this.state.count}</h2>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}

export default LifecycleDemo;

πŸ” What is an Event in React?

An event in React is an action or user interaction (like a click, input, or keypress) that triggers a function to run β€” similar to JavaScript DOM events.

βœ… Example of Event in React:

function MyButton() {
const handleClick = () => {
alert("Button clicked!");
};

return <button onClick={handleClick}>Click Me</button>;
}
  • onClick is the event listener
  • handleClick is the event handler function

🧠 What is a Synthetic Event in React?

A SyntheticEvent is React’s cross-browser wrapper around the native browser event.
It wraps native events (like click, submit, change, etc.) and normalizes them so they behave consistently across all browsers.

πŸ”§ Features of SyntheticEvent:

  • Has the same interface as a native browser event.
  • Works identically across browsers (standardized behavior).
  • Supports event pooling (for performance, but deprecated in React 17+).
  • Supports preventDefault() and stopPropagation() like native events.

βœ… Example Using SyntheticEvent:

function InputExample() {
const handleChange = (event) => {
console.log("Input value:", event.target.value); // SyntheticEvent
};

return <input type="text" onChange={handleChange} />;
}

Here, event is a SyntheticEvent, not a raw DOM event.

πŸ” What is ref in React?

ref (reference) is used in React to access and interact with DOM elements or React elements directly β€” outside the normal React data flow.

βœ… Use Cases of ref:

Integrate with third-party libraries

Focus or blur an input element

Trigger animations

Read or modify DOM properties directly

import React, { useRef } from "react";

function TextInputFocus() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus(); // Access the DOM element directly
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={handleClick}>Focus Input</button>
    </div>
  );
}

πŸ”§ How to Modularize Code in React

Modularizing code means breaking your app into small, reusable, and manageable components and files. This improves readability, maintainability, testing, and scalability.

Break large components into smaller, reusable ones.

Use a clear folder structure:

use export and import properties

πŸ”„ React.forwardRef() – Explained Simply

React.forwardRef() is a special React function that allows you to forward a ref from a parent to a child component β€” especially when the child is a functional component.

Normally, refs don’t work directly on functional components because they don’t have an instance. forwardRef fixes that by passing the ref down to a DOM element or another component.

πŸ“Œ Why use forwardRef()?

  • When you want parent access to child DOM elements (e.g., focus, scroll, select).
  • When using 3rd-party component libraries that require DOM refs.
  • To build reusable, composable input components.
import React, { useRef } from "react";

// πŸ‘‡ Child component using forwardRef
const CustomInput = React.forwardRef((props, ref) => {
  return <input type="text" ref={ref} placeholder="Type here" />;
});

function App() {
  const inputRef = useRef(null);

  const focusInput = () => {
    inputRef.current.focus(); // Access input inside child
  };

  return (
    <div>
      <CustomInput ref={inputRef} />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
}

export default App;

πŸ” React.createRef() in React

React.createRef() is used in class components to create a ref object that can be attached to a DOM element or React component to directly access it.

import React from "react";

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.inputRef = React.createRef(); // πŸ‘ˆ Create ref
  }

  focusInput = () => {
    this.inputRef.current.focus(); // πŸ‘ˆ Access the DOM node
  };

  render() {
    return (
      <div>
        <input type="text" ref={this.inputRef} />
        <button onClick={this.focusInput}>Focus Input</button>
      </div>
    );
  }
}

export default MyComponent;

πŸ“ How to Create a Form in React

Forms in React are created using controlled components, where the form inputs are connected to component state using useState() (for functional components) or this.state (for class components).

βœ… Functional Component Example (Using useState)

import React, { useState } from 'react';

function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: ''
});

const handleChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value // dynamically updates 'name' or 'email'
});
};

const handleSubmit = (e) => {
e.preventDefault();
alert(`Name: ${formData.name}, Email: ${formData.email}`);
};

return (
<form onSubmit={handleSubmit}>
<label>
Name: <input type="text" name="name" value={formData.name} onChange={handleChange} />
</label><br />
<label>
Email: <input type="email" name="email" value={formData.email} onChange={handleChange} />
</label><br />
<button type="submit">Submit</button>
</form>
);
}

export default ContactForm;

βœ… Class Component Example (Optional)

class ContactForm extends React.Component {
constructor(props) {
super(props);
this.state = { name: '', email: '' };
}

handleChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
}

handleSubmit = (e) => {
e.preventDefault();
alert(`Name: ${this.state.name}, Email: ${this.state.email}`);
}

render() {
return (
<form onSubmit={this.handleSubmit}>
<input name="name" value={this.state.name} onChange={this.handleChange} />
<input name="email" value={this.state.email} onChange={this.handleChange} />
<button type="submit">Submit</button>
</form>
);
}
}

πŸ” Controlled vs Uncontrolled Components in React

These are two ways to handle form inputs in React.

βœ… Controlled Component

A component where form data is handled by React state.

πŸ”§ Characteristics:

  • Uses useState (or this.state)
  • React controls the input’s value
  • Always updates via onChange

πŸ§ͺ Example:

function ControlledInput() {
const [value, setValue] = React.useState('');

return (
<input
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
}

βœ… Advantages:

  • Easier validation
  • Single source of truth
  • React has full control

❌ Uncontrolled Component

A component where form data is handled by the DOM (not React).

πŸ”§ Characteristics:

  • Uses ref to access DOM node
  • No state tracking of input value
  • Browser manages the input’s current value

πŸ§ͺ Example:

function UncontrolledInput() {
const inputRef = React.useRef();

const handleSubmit = () => {
alert(inputRef.current.value); // Access DOM value directly
};

return (
<>
<input type="text" ref={inputRef} />
<button onClick={handleSubmit}>Submit</button>
</>
);
}

βœ… Advantages:

  • Simpler for quick forms
  • Less React code
  • Slightly better performance in large forms

πŸ” Comparison Table

FeatureControlledUncontrolled
Data SourceReact StateDOM
Access Valuestateref.current.value
React ControlFullMinimal
Use CaseValidation, dynamic UI, logic-based formsSimple or 3rd-party uncontrolled forms
Re-render on inputβœ… Yes❌ No

🧠 Summary:

  • Use Controlled Components for complex logic, validation, or multi-step forms.
  • Use Uncontrolled Components for simpler or read-only scenarios.

πŸ” What is a HOC (Higher-Order Component) in React?

A Higher-Order Component (HOC) is a function that takes a component as input and returns a new enhanced component.

Think of it as a component wrapper that adds reusable behavior (like logging, access control, or data fetching).

const EnhancedComponent = higherOrderComponent(WrappedComponent);

🧠 Real Example:

// HOC that adds loading spinner behavior
function withLoading(Component) {
return function EnhancedComponent({ isLoading, ...props }) {
if (isLoading) return <p>Loading...</p>;
return <Component {...props} />;
};
}

βœ… Usage:

function UserList({ users }) {
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}

const UserListWithLoading = withLoading(UserList);


// Rendering this in JSX:
<UserListWithLoading isLoading={false} users={['Ved', 'Amit']} />

πŸ“Œ Key Characteristics:

FeatureDescription
TypePure function (no JSX inside HOC itself)
ReusabilityAdds logic to multiple components
Props PassingMust pass down ...props to wrapped component
NamingConvention: withSomething (e.g., withAuth)
Similar ToLike a middleware for React components

⚠️ Common Use Cases:

  • Authentication checks (withAuth)
  • Loading spinners (withLoading)
  • Error boundaries
  • Logging/metrics
  • Code reuse for data fetching

πŸ” What is the Props Proxy Pattern?

In a props proxy HOC, the HOC intercepts and manipulates props before passing them to the wrapped component.

function withPropsProxy(WrappedComponent) {
  return function EnhancedComponent(props) {
    const newProps = {
      ...props,
      injectedProp: 'new property',
    };

    return <WrappedComponent {...newProps} />;
  };
}

πŸ” What is a Pure Component in React?

A Pure Component in React is a class component that implements automatic shallow comparison in its shouldComponentUpdate() method to prevent unnecessary re-renders.

πŸ” Example:

class RegularComponent extends React.Component {
render() {
console.log('RegularComponent rendered');
return <div>{this.props.message}</div>;
}
}

class OptimizedComponent extends React.PureComponent {
render() {
console.log('PureComponent rendered');
return <div>{this.props.message}</div>;
}
}

Now, if message doesn’t change:

  • RegularComponent will still render
  • PureComponent will skip rendering

πŸ”‘ What is key in React?

In React, a key is a special string attribute you must include when rendering a list of elements. It helps React identify which items have changed, added, or removed efficiently during re-rendering.

const users = ['Ved', 'Amit', 'Sara'];

function UserList() {
  return (
    <ul>
      {users.map((user, index) => (
        <li key={user}>{user}</li>  // πŸ”‘ key is important here
      ))}
    </ul>
  );
}

πŸ”„ What is React Redux?

Redux is a state management library for JavaScript apps, often used with React. It allows you to centralize application state and manage it in a predictable way.

πŸ”Ί 3 Core Principles of Redux

  1. Single Source of Truth
    • All app state is stored in a single store.
  2. State is Read-Only
    • The only way to change state is to dispatch an action, not mutate it directly.
  3. Changes via Pure Functions (Reducers)
    • State transitions are handled by pure functions called reducers.

🧱 Key Components of Redux

ComponentDescription
ActionsPlain JS objects describing what happened
ReducersFunctions that take state & action β†’ return new state
StoreHolds the application state and provides methods to access, dispatch, and subscribe
ProviderReact-Redux component that makes the Redux store available to child components
connect / hooksTo connect React components to the Redux store (e.g. useSelector, useDispatch)

πŸ” Data Flow in Redux

Component β†’ dispatch(action)
↓
Reducer (pure function)
↓
New State (updated store)
↓
React Component re-renders

πŸ”§ Defining an Action

An action is a plain object with a type field:

// action.js
export const increment = () => ({
type: 'INCREMENT'
});

You can also pass a payload:

export const setUser = (user) => ({
type: 'SET_USER',
payload: user
});

🧠 Role of Reducers

A reducer is a pure function that receives the current state and an action, and returns the new state:

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

🏬 What is a Redux Store?

The store is the central location that:

  • Holds the state
  • Allows access via getState()
  • Allows updates via dispatch(action)
  • Allows subscription via subscribe()
import { createStore } from 'redux';
const store = createStore(counterReducer);

πŸ“¦ React-Redux Integration

// index.js
import { Provider } from 'react-redux';
import App from './App';
import store from './store';

<Provider store={store}>
<App />
</Provider>

In your component:

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

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

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

βœ… store.subscribe() – What it does

It registers a callback function that gets called every time the Redux store’s state changes.

πŸ§ͺ Syntax:

const unsubscribe = store.subscribe(() => {
console.log('State changed:', store.getState());
});
  • subscribe() returns an unsubscribe function.
  • Call it to stop listening to changes.

πŸ”„ Flux vs Redux

FeatureFluxRedux
ArchitectureMultiple storesSingle store
DispatcherRequiredNot used
Data MutationMutable via storeImmutable via reducer
State StorageInside multiple storesInside a single store
BoilerplateMore complexSimplified with Redux Toolkit

βœ… Advantages of Redux

  • πŸ“Œ Predictable state updates
  • avoid prop drilling
  • πŸ” Centralized global state
  • πŸ§ͺ Easier debugging (DevTools)
  • πŸ“€ Decouples state from components
  • πŸ”§ Great for large-scale applications
  • πŸ” Time-travel debugging
  • 🧩 Ecosystem: middleware, dev tools, toolkit

There are several alternatives to Redux for state management in React, depending on your app’s complexity, scalability needs, and developer preference. some example: ContextApi, MOBX, Appolo Client + GraphQL, RXJS

πŸ” Redux vs Context API in React – What’s the Difference?

Both Redux and React Context API help in managing global state, but they are fundamentally different tools with different use cases, power, and complexity. Context Api is built-in React feature for passing global data (like themes, user info, etc.) without prop drilling. while Redux is a standalone state management library (can be used outside React) that manages application state using a central store, actions, and reducers.

πŸ”₯ Main Difference Between redux and react-redux

reduxreact-redux
What it isCore library to create and manage global stateBinding library to connect Redux to React components
ProvidescreateStore(), combineReducers(), applyMiddleware()Provider, useDispatch(), useSelector(),
Note: connect() Before React Hooks (useSelector, useDispatch), this was the primary way to access Redux state and dispatch actions in class-based or functional components.
UsageUsed to build the Redux store and reducersUsed to make React components aware of Redux state
React-specific?❌ No (can be used with Vue, Angular, etc.)βœ… Yes (designed only for React)

πŸ”„ What is React Router?

React Router is a popular library used in React applications to handle client-side routing β€” i.e., navigating between different views/components without refreshing the browser.

🧱 Core Concepts in React Router

ConceptDescription
BrowserRouterEnables routing using browser’s history API (clean URLs)
RoutesContainer for all route definitions
RouteDefines the path and the component to render
Link / NavLinkUsed for navigation (like <a>, but without reload)
useParams, useNavigate, useLocationReact Router hooks for dynamic routing, navigation, etc.

βœ… Example: Basic React Router Setup

import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
import Home from './Home';
import About from './About';

function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Home</Link> | <Link to="/about">About</Link>
</nav>

<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
}

🌐 What is BrowserRouter?

  • Uses HTML5 history API (pushState, popState) for clean URLs (e.g., /home, /about)
  • Keeps the UI in sync with the URL without reloading the page
  • Must wrap your app inside it to enable routing

βœ… Advantages of React Router

AdvantageDescription
SPA SupportEnables Single Page Application behavior
No Page ReloadsNavigation is fast and dynamic
Dynamic RoutingSupports params, nested routes, and lazy loading
Route ProtectionCan add guards based on auth logic
Clean URLsUses browser history (BrowserRouter)
Hook SupportuseParams, useNavigate, etc., simplify routing logic

πŸ“Š Conventional Routing vs React Routing

FeatureConventional Routing (e.g., PHP, server-rendered)React Routing (SPA)
Routing TypeServer-sideClient-side (JS in browser)
Page ReloadFull reload on every route changeNo reload
SpeedSlower (due to server calls)Faster (JS handles it instantly)
Data FetchEach route triggers a new requestCan fetch data conditionally
URL MappingServer determines what page to serveReact component renders view
SEOBetter out of the boxNeeds SSR (e.g. Next.js) for SEO

πŸš€ Extra: Nested Routes Example

<Routes>
<Route path="/dashboard" element={<Dashboard />}>
<Route path="settings" element={<Settings />} />
<Route path="profile" element={<Profile />} />
</Route>
</Routes>

URL example: /dashboard/settings

πŸ” setState() vs replaceState() in React

βœ… setState()

  • Merges the new state with the existing state.
  • Partial update β†’ only updates the keys you specify.
  • Commonly used in both class components and

❌ replaceState() (Deprecated)

  • Replaces the entire state object instead of merging.

🌐 Components of React Router: BrowserRouter vs HashRouter vs MemoryRouter

React Router provides several router components to control how the routing works depending on the environment and URL handling needs.

πŸ” 1. BrowserRouter – Most Common for Web Apps

βœ… Uses the HTML5 History API (pushState, popState)
🌍 URL looks clean: /home, /about

βœ… Example:

import { BrowserRouter, Route, Routes } from 'react-router-dom';
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>

⚠ Requirements:

  • Server must be configured to return index.html for all routes (otherwise 404 on refresh)

πŸ”’ 2. HashRouter – For Static File Hosts (GitHub Pages, etc.)

βœ… Uses the hash (#) portion of the URL
🌐 URLs look like: http://example.com/#/about

βœ… Example:

import { HashRouter, Route, Routes } from 'react-router-dom';
<HashRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</HashRouter>

πŸ”§ Good For:

  • Apps hosted on static file servers with no server-side routing support

🧠 3. MemoryRouter – In-Memory History (No URL changes)

βœ… Keeps routing in memory (no interaction with browser URL)
πŸ§ͺ Commonly used in unit tests, React Native, or non-browser environments

βœ… Example:

import { MemoryRouter, Route, Routes } from 'react-router-dom';
<MemoryRouter initialEntries={['/about']}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</MemoryRouter>

⚑ Boost React Performance – Top Tips

⚑ 1. Use React.memo() for Functional Components

Wrap components with React.memo to avoid re-rendering unless props change.

const MyComponent = React.memo(function MyComponent(props) {
return <div>{props.value}</div>;
});

🧠 2. Use useCallback and useMemo

Prevent unnecessary re-creation of functions and values.

const memoizedCallback = useCallback(() => doSomething(a, b), [a, b]);
const memoizedValue = useMemo(() => computeExpensiveValue(x), [x]);

πŸ—οΈ 3. Code Splitting with React.lazy() and Suspense

Split code by routes/components to reduce initial load size.

const LazyComponent = React.lazy(() => import('./MyComponent'));

🧹 4. Avoid Inline Functions in JSX

They create a new function on every render, breaking memoization.

❌ Bad:

<button onClick={() => doSomething()}>Click</button>

βœ… Good:

const handleClick = useCallback(() => doSomething(), []);
<button onClick={handleClick}>Click</button>

🧱 5. Use Key Wisely in Lists

Avoid using array indices as keys in dynamic lists. Use stable unique IDs.

🧩 6. Virtualize Long Lists

Use libraries like react-window or react-virtualized for large lists.

πŸ”„ 7. Debounce Expensive Operations

Like search inputs or resize events β€” use lodash.debounce or useDebounce.

πŸ§ͺ 8. Keep Component State Local Where Needed

Avoid putting everything in global context or Redux β€” local state is faster.

🚫 9. Avoid Unnecessary Re-renders

Use tools like:

  • React Developer Tools
  • why-did-you-render library (for debugging excessive renders)

🌍 10. Enable Production Build

For deployment, always build with npm run build to enable minification and performance optimizations.

πŸ” What is Shallow Comparison in React?

Shallow comparison means comparing primitive values directly and objects/arrays by reference, not by their internal contents.

Used mainly in:

  • React.PureComponent
  • React.memo()
  • shouldComponentUpdate()

⚠️ Limitation

It does NOT check deep equality of nested values:

const a = { user: { name: "Ved" } };
const b = { user: { name: "Ved" } };

a === b; // false – different references

So if you update nested object values without changing reference, React may not re-render.

πŸ“˜ React Context API (v16.3+)

The Context API (introduced in React 16.3) provides a way to share global data (like themes, auth, language, etc.) across components without passing props manually at every level.

🧱 Main Parts of Context API

PartDescription
React.createContext()Creates a Context object
ProviderProvides context data to the component tree
ConsumerConsumes context data (older way)
useContext()Hook to consume context in functional components (from v16.8)

βœ… Example (React 16.3 – Class Component)

// 1. Create Context
const MyContext = React.createContext();

// 2. Create Provider
class MyProvider extends React.Component {
state = {
name: 'Ved',
role: 'Admin'
};

render() {
return (
<MyContext.Provider value={this.state}>
{this.props.children}
</MyContext.Provider>
);
}
}

// 3. Consume in Class Component
class MyConsumer extends React.Component {
render() {
return (
<MyContext.Consumer>
{context => (
<div>
<p>Name: {context.name}</p>
<p>Role: {context.role}</p>
</div>
)}
</MyContext.Consumer>
);
}
}

βœ… Modern Way (Post-16.8: Functional + useContext())

import React, { createContext, useContext } from 'react';

const ThemeContext = createContext();

const App = () => {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
};

const Toolbar = () => {
return <ThemedButton />;
};

const ThemedButton = () => {
const theme = useContext(ThemeContext); // βœ… Consume context
return <button className={theme}>I am styled with {theme} theme</button>;
};

🧠 Why Use Context API?

Use CaseExample
Theme switchingLight/Dark mode
Authentication infoUser logged in status, token
Language localizationEnglish / Hindi, etc.
Global config or settingsAPI URLs, toggles

πŸ“¦ What is PropTypes in React?

PropTypes is a built-in React utility (via the prop-types package) used to validate props passed to a component. It helps catch bugs by ensuring the right type of props are passed at runtime.

//npm install prop-types

import React from 'react';
import PropTypes from 'prop-types';

function Welcome({ name, age }) {
  return <h1>Hello {name}, age {age}</h1>;
}

// βœ… PropTypes definition
Welcome.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number
};

// βœ… Default props (optional)
Welcome.defaultProps = {
  age: 18
};

export default Welcome;

🧩 Common PropTypes

PropTypes SyntaxDescription
PropTypes.stringMust be a string
PropTypes.numberMust be a number
PropTypes.boolMust be a boolean
PropTypes.funcMust be a function
PropTypes.arrayMust be an array
PropTypes.objectMust be an object
PropTypes.nodeAnything renderable (string, element, fragment, etc.)
PropTypes.elementA React element
PropTypes.anyAny type
PropTypes.symbolA JS Symbol

πŸ§ͺ Advanced Examples

πŸ”Έ Optional & Required:

ttitle: PropTypes.string,              // optional
title: PropTypes.string.isRequired, // required

πŸ”Έ One of Specific Values

size: PropTypes.oneOf(['small', 'medium', 'large']),

πŸ”Έ One of Multiple Types

id: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number
]),

πŸ”Έ Array of Specific Types

scores: PropTypes.arrayOf(PropTypes.number),

πŸ”Έ Object of Specific Shape

user: PropTypes.shape({
id: PropTypes.number,
name: PropTypes.string.isRequired
}),

πŸ”„ What is Memoization in React?

Memoization is an optimization technique that caches the result of a function or component so it only re-computes or re-renders when inputs change. This avoids unnecessary work and boosts performance.

βœ… React Memoization Tools

ToolUse Case
React.memoMemoize a component
useMemo()Memoize a value/result
useCallback()Memoize a function

1️⃣ React.memo (Component-level Memoization)

Prevents re-rendering unless props change. React.memo is just a HOC.

const MyComponent = React.memo(({ name }) => {
console.log("Rendering MyComponent");
return <h1>Hello {name}</h1>;
});

2️⃣ useMemo() (Value-level Memoization)

Caches expensive values unless dependencies change.

const expensiveValue = useMemo(() => {
return computeHeavyTask(input);
}, [input]);

3️⃣ useCallback() (Function-level Memoization)

Caches functions so they don’t get recreated on every render.

const handleClick = useCallback(() => {
console.log("Clicked!");
}, []);

πŸ“‘ API Calls in React – GET, POST, PUT, DELETE

Learn how to make different types of API requests in React using fetch() and axios.

πŸ” HTTP Methods Overview

MethodPurpose
GETRetrieve data
POSTAdd new data
PUTUpdate existing data
DELETERemove data

🌐 Example API Endpoints

HTTP MethodExample PathUse Case
GET/api/usersFetch all users
POST/api/usersAdd a new user
PUT/api/users/:idUpdate user by ID
DELETE/api/users/:idDelete user by ID

βš™οΈ Using fetch() (Native)

βœ… GET

useEffect(() => {
fetch('/api/users')
.then(res => res.json())
.then(data => setUsers(data));
}, []);

βœ… POST

fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Ved', age: 30 })
});

βœ… PUT

fetch('/api/users/1', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ age: 31 })
});

βœ… DELETE

fetch('/api/users/1', {
method: 'DELETE'
});

βš™οΈ Using axios (Recommended)

βœ… Setup

npm install axios

βœ… Usage

import axios from 'axios';

// GET
axios.get('/api/users').then(res => setUsers(res.data));

// POST
axios.post('/api/users', { name: 'Ved', age: 30 });

// PUT
axios.put('/api/users/1', { age: 31 });

// DELETE
axios.delete('/api/users/1');

🧠 React Hooks – Complete Guide (Latest Version)

Hooks let you use state and other React features in functional components β€” without writing class components.

βœ… 1. useState()

πŸ“˜ Description:

useState allows functional components to have local state. It’s the most basic and frequently used hook.

πŸ§ͺ Syntax:

const [state, setState] = useState(initialValue);

βœ… 2. useEffect()

πŸ“˜ Description:

useEffect is used to perform side effects in function components, such as:

  • Data fetching
  • Subscribing/unsubscribing
  • DOM manipulation
  • Setting up timers

It replaces lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount.

πŸ§ͺ Syntax:

useEffect(() => {
// effect logic
return () => {
// cleanup logic (optional)
};
}, [dependencies]);

🧠 Example – Fetching Data:

import { useEffect, useState } from 'react';

function UserList() {
const [users, setUsers] = useState([]);

useEffect(() => {
fetch('/api/users')
.then(res => res.json())
.then(data => setUsers(data));
}, []); // Empty dependency array β†’ run once after mount

return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}

πŸ”„ useEffect() Dependency Array Behavior

Dependency ArrayBehavior in Class Component (Equivalent)
[]βœ… componentDidMount (runs once on mount)
[count]βœ… componentDidUpdate (runs when count changes)
(no array)βœ… Both componentDidMount and componentDidUpdate β€” runs after every render (initial + updates)

Class ComponentFunctional Component Equivalent
componentWillUnmountuseEffect(() => { return () => {} }, [])

βœ… 3. useContext()

πŸ“˜ Description:

useContext() is used to access context values in a functional component β€” replacing the older <Context.Consumer> pattern. It allows you to share global data (like theme, user info, language, etc.) across the component tree without passing props manually at every level.

πŸ§ͺ Syntax:

const value = useContext(MyContext);

🧠 Example:

// 1. Create context
const ThemeContext = React.createContext('light');

function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}

// 2. Use context
function Toolbar() {
const theme = useContext(ThemeContext);
return <button className={theme}>I am {theme} themed</button>;
}

βœ… 4. useRef()

πŸ“˜ Description:

useRef() is a React Hook that:

  • Gives you a mutable reference object that persists across renders.
  • Commonly used to access DOM elements directly.
  • Also used to store values that don’t trigger re-render when updated.
import { useRef } from 'react';

function TextInput() {
  const inputRef = useRef();

  const focusInput = () => {
    inputRef.current.focus(); // Access DOM element directly
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
}

βœ… 5. useMemo()

πŸ“˜ Description:

useMemo() is a React hook used to memoize (cache) expensive calculations so they are only recomputed when their dependencies change.

πŸ” Example: Expensive Calculation

import { useMemo, useState } from 'react';

function FibonacciCalculator({ n }) {
const fib = useMemo(() => {
console.log("Calculating Fibonacci...");
const fibonacci = (n) => {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
};
return fibonacci(n);
}, [n]);

return <h3>Fib({n}) = {fib}</h3>;
}

⚠️ Without useMemo:

The expensive fibonacci() function would re-run on every render, even if n hasn’t changed. That’s slow.

βœ… 6. useCallback()

πŸ“˜ Description:

useCallback() is a React hook that returns a memoized version of a function, which is only re-created when one of its dependencies changes. Use it to prevent unnecessary re-creations of functions β€” especially helpful when passing callbacks to child components.

πŸ” Example:

//syntax
const memoizedCallback = useCallback(() => {
// function logic
}, [dependencies]);

//code
import { useState, useCallback } from 'react';

function Counter() {
const [count, setCount] = useState(0);

const increment = useCallback(() => {
setCount(prev => prev + 1);
}, []); // Will not re-create on each render

return (
<div>
<p>Count: {count}</p>
<Button onClick={increment} />
</div>
);
}

function Button({ onClick }) {
console.log("Button rendered");
return <button onClick={onClick}>Increment</button>;
}

βœ… 7. useReducer()

πŸ“˜ Description:

useReducer() is an alternative to useState() for managing complex state logic β€” especially when:

  • State depends on previous state
  • Multiple related state transitions are involved

It’s similar to Redux-style reducers but scoped within a component.

πŸ§ͺ Syntax:
const [state, dispatch] = useReducer(reducerFunction, initialState);
import { useReducer } from 'react';

const initialState = { count: 0 };

// Reducer function
function reducer(state, action) {
  switch (action.type) {
    case 'increment': return { count: state.count + 1 };
    case 'decrement': return { count: state.count - 1 };
    default: return state;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </div>
  );
}

βœ… When to Use useReducer()

SituationUse useReducer()?
Complex state with multiple actionsβœ… Yes
State derived from previous stateβœ… Yes
Simple toggle or single field state❌ useState() is simpler

βœ… 8. useLayoutEffect()

πŸ“˜ Description:

useLayoutEffect() is just like useEffect(), but it runs synchronously after all DOM mutations but before the browser repaints.

This means:

  • It blocks painting until the effect is complete.
  • Useful when you need to measure DOM elements or make visual updates immediately.

πŸ§ͺ Syntax:

useLayoutEffect(() => {
// Do something immediately after DOM update
return () => {
// Cleanup (optional)
};
}, [dependencies]);

⚠️ Difference from useEffect()

FeatureuseEffect()useLayoutEffect()
Runs after render?βœ… Yes (async)βœ… Yes (sync, before paint)
Affects paint?❌ No (runs after paint)βœ… Yes (can block paint)
UsageAPI calls, timers, cleanupDOM measurements, animations

βœ… 9. useImperativeHandle()

πŸ“˜ Description:

useImperativeHandle() is a React hook used with forwardRef() to let child components expose specific methods or properties to the parent.

It’s useful when the parent needs to control or call functions inside the child component, but you want to control exactly what’s exposed β€” instead of giving full access to the DOM or internal state.

πŸ§ͺ Syntax:

useImperativeHandle(ref, () => ({
method1,
method2,
// only expose what you want
}), [dependencies]);

βš™οΈ Example: Expose a Focus Method from a Child Input

import React, { useRef, useImperativeHandle, forwardRef } from 'react';

// 1. Child component with forwardRef
const CustomInput = forwardRef((props, ref) => {
const inputRef = useRef();

// 2. Expose methods to parent
useImperativeHandle(ref, () => ({
focusInput: () => inputRef.current.focus()
}));

return <input ref={inputRef} type="text" />;
});

// 3. Parent component
function Parent() {
const inputRef = useRef();

return (
<div>
<CustomInput ref={inputRef} />
<button onClick={() => inputRef.current.focusInput()}>
Focus from Parent
</button>
</div>
);
}

🧠 When to Use useImperativeHandle():

Use Caseβœ… Use it?
Parent needs to control child’s functionβœ… Yes
Custom modal, input, form handlingβœ… Yes
You want to expose only specific methodsβœ… Yes
Simple DOM access only❌ Use useRef() directly

βœ… 10. useId() (React 18+)

πŸ“˜ Description:

useId() is a React 18+ hook used to generate unique, stable IDs for accessibility and SSR (Server-Side Rendering) support.

It’s helpful for linking form elements like <label> and <input> β€” especially when:

  • You need unique IDs in multiple instances of a component
  • You’re using SSR and want to prevent ID mismatches

πŸ§ͺ Syntax:

const id = useId();

🧠 Example: Accessible Form Input

import { useId } from 'react';

function NameInput() {
const id = useId(); // unique ID for this component instance

return (
<div>
<label htmlFor={id}>Name:</label>
<input id={id} type="text" />
</div>
);
}

Do not call useId() inside .map() β€” that’s invalid in React. Yes, you can define multiple unique IDs in a component β€” but you must not define them inside loops using hooks like useId().

βœ… 11. useDebugValue()

useDebugValue() is a React Hook used only for debugging custom hooks in React DevTools.

useDebugValue(isOnline ? 'Online' : 'Offline');

In React DevTools, this hook will now display:
🟒 useOnlineStatus: "Online" or πŸ”΄ "Offline"

βœ… What Are Custom Hooks?

A custom hook is a JavaScript function whose name starts with use, and it can use other hooks internally (like useState, useEffect, etc.).

🎯 Goal: Extract and reuse logic across multiple components without duplicating code.

🧱 Basic Syntax

function useCustomHook() {
// use other hooks like useState, useEffect
return something;
}

πŸ” Example 1: useCounter (Simple Reusable Hook)

import { useState } from 'react';

function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);

const increment = () => setCount(prev => prev + 1);
const decrement = () => setCount(prev => prev - 1);
const reset = () => setCount(initialValue);

return { count, increment, decrement, reset };
}

βœ… Use it in any component:

function CounterComponent() {
const { count, increment, decrement, reset } = useCounter(5);
return (
<div>
<p>{count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>βˆ’</button>
<button onClick={reset}>Reset</button>
</div>
);
}

βœ… Benefits of Custom Hooks

BenefitDescription
β™» ReusabilityShare logic between components easily
πŸ“¦ Separation of ConcernsUI and logic live separately
πŸ” Clean CodeRemoves duplication, makes components smaller
πŸ§ͺ Easy TestingHook logic can be tested independently

βš›οΈ React Hook Rules

  • Only call hooks at the top level
  • Only call hooks from React functions

πŸš€ What is Concurrent React?

Concurrent rendering allows React to interrupt long rendering tasks and give priority to more important updates (like typing or animations).

⚑️ React 18 enables this with features like startTransition, useTransition, useDeferredValue, and automatic batching.

βœ… 1. startTransition() – Mark Updates as Non-Urgent

πŸ“˜ Description:

Used to mark state updates that are non-urgent, so React can delay them if needed β€” like updating search results while the user types.

πŸ§ͺ Example:

import { useState, startTransition } from 'react';

function SearchComponent() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);

function handleChange(e) {
const value = e.target.value;
setQuery(value);

// Mark as low priority
startTransition(() => {
const filtered = slowSearch(value); // assume slow function
setResults(filtered);
});
}

return (
<>
<input value={query} onChange={handleChange} />
<ul>{results.map(r => <li key={r}>{r}</li>)}</ul>
</>
);
}

βœ… 2. useTransition() – User-Friendly Way to Handle Transitions

πŸ“˜ Description:

A hook version of startTransition() that also tells you if the transition is pending (still in progress).

πŸ§ͺ Example:

import { useState, useTransition } from 'react';

function ProductFilter({ products }) {
const [input, setInput] = useState('');
const [filtered, setFiltered] = useState(products);
const [isPending, startTransition] = useTransition();

const handleChange = (e) => {
const value = e.target.value;
setInput(value);

startTransition(() => {
const result = products.filter(p => p.includes(value));
setFiltered(result);
});
};

return (
<div>
<input value={input} onChange={handleChange} />
{isPending && <p>Loading...</p>}
<ul>{filtered.map(p => <li key={p}>{p}</li>)}</ul>
</div>
);
}

βœ… 3. useDeferredValue() – Defer Heavy Calculations

πŸ“˜ Description:

Defer updates to less important values so they update after more urgent ones (like input typing).

πŸ§ͺ Example:

import { useState, useDeferredValue } from 'react';

function SearchList({ data }) {
const [input, setInput] = useState('');
const deferredInput = useDeferredValue(input); // updates slower

const filtered = data.filter(item =>
item.toLowerCase().includes(deferredInput.toLowerCase())
);

return (
<>
<input value={input} onChange={e => setInput(e.target.value)} />
<ul>{filtered.map(item => <li key={item}>{item}</li>)}</ul>
</>
);
}

React Router v6 Hooks – useNavigate(), useLocaton(), useParams()

useNavigate() replaces history.push() and history.replace(). In older versions (v5 and below), you used history.push directly.

import { useNavigate } from 'react-router-dom';

const Component = () => {
const navigate = useNavigate();

// Push (adds to history stack)
const goToProfile = () => {
navigate('/profile');
};

// Replace (replaces current entry in history stack)
const replaceWithHome = () => {
navigate('/', { replace: true });
};

return (
<>
<button onClick={goToProfile}>Go to Profile</button>
<button onClick={replaceWithHome}>Replace with Home</button>
</>
);
};

🧭 push vs replace

MethodBehavior
navigate(path)Adds a new entry to the browser history stack
navigate(path, { replace: true })Replaces the current entry (like redirect)

πŸ“¦ Passing Parameters with push / navigate

There are two common ways to pass data:

1. Using URL Params (Path Params)

navigate(`/user/${userId}`);

In route:

<Route path="/user/:id" element={<User />} />

In component:

const { id } = useParams();

2. Using state (Hidden / Non-URL)

tnavigate('/profile', { state: { name: 'Ved', role: 'admin' } });

And then access it in the target component:

import { useLocation } from 'react-router-dom';
const Profile = () => {
const location = useLocation();
const { name, role } = location.state || {};

return (
<div>
<h1>{name}'s Profile</h1>
<p>Role: {role}</p>
</div>
);
};

βœ… Advantage: cleaner URL, good for passing complex data
❌ Data is lost on full page reload (no persistence)

βœ… 4. Automatic Batching

πŸ“˜ Description:

In React 18+, multiple state updates inside:

  • Timeouts
  • Promises
  • Event handlers
    …are batched together to prevent unnecessary re-renders.

πŸ§ͺ Before vs After:

setCount1(c => c + 1);
setCount2(c => c + 1);

βœ… In React 18+, this is automatically batched β€” only one render occurs.

πŸ“Œ Summary Table

FeaturePurpose
startTransitionMark updates as low priority
useTransitionHook to manage transitions + pending state
useDeferredValueDelay updates for performance
Automatic BatchingGroup multiple updates β†’ fewer renders
SuspenseAsync UI handling

πŸš€ What is the React Profiler?

The React Profiler is a built-in tool in the React Developer Tools extension. It helps you:

  • Measure how often components render
  • See what caused re-renders
  • Identify slow renders and unnecessary updates

πŸ”§ What is Redux Thunk?

A thunk is a function that wraps an expression to delay its evaluation.

In Redux, a thunk is a function that returns another function β€” this lets you delay dispatching actions or dispatch asynchronous actions (like API calls).

πŸ’¬ In simple terms:

It allows action creators to return a function instead of an action object.

πŸš€ Why Use Redux Thunk?

Redux’s dispatch() only handles plain objects.
To handle API calls, delayed actions, or any side-effects, you need middleware like redux-thunk.

πŸ“¦ How to Set Up Thunk

1. Install:

npm install redux-thunk

2. Apply it to the store:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

const store = createStore(rootReducer, applyMiddleware(thunk));

πŸ“˜ Thunk Action Creator Syntax

const fetchUsers = () => {
return function (dispatch) {
dispatch({ type: 'FETCH_USERS_REQUEST' });

fetch('https://jsonplaceholder.typicode.com/users')
.then(res => res.json())
.then(data =>
dispatch({ type: 'FETCH_USERS_SUCCESS', payload: data })
)
.catch(error =>
dispatch({ type: 'FETCH_USERS_FAILURE', payload: error })
);
};
};

βœ… This is a thunk: returns a function instead of a plain object

πŸ” Using Thunk in Component

import { useDispatch, useSelector } from 'react-redux';
import { fetchUsers } from './actions/userActions';

function UserList() {
const dispatch = useDispatch();
const { users, loading } = useSelector(state => state.user);

useEffect(() => {
dispatch(fetchUsers()); // Thunk is triggered
}, []);

if (loading) return <p>Loading...</p>;

return (
<ul>
{users.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
);
}

βœ… Benefits of Redux Thunk

FeatureDescription
Async SupportHandles API calls, timeouts, etc.
Logic outside componentsKeeps components cleaner
Fine-grained controlDispatch multiple actions manually
Easy to debugFollows normal function pattern

❌ Downsides

  • Can lead to callback hell for complex flows
  • Not as structured as redux-saga or redux-observable
  • Logic can get spread out if not modularized well

Complete Redux setup example

complete Redux setup example with a modular folder structure for a store that manages multiple objects (like user, posts, etc.)

πŸ—‚ Folder Structure:

/redux
/store.js
/reducers
index.js
userReducer.js
postReducer.js
/actions
userActions.js
postActions.js

1️⃣ redux/store.js – Store Configuration

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

const store = createStore(rootReducer, applyMiddleware(thunk));

export default store;

πŸ“Œ Explanation:

  • createStore creates the Redux store
  • thunk allows async actions
  • Uses rootReducer (combined reducers)

2️⃣ redux/reducers/index.js – Combine Reducers

import { combineReducers } from 'redux';
import userReducer from './userReducer';
import postReducer from './postReducer';

const rootReducer = combineReducers({
user: userReducer,
post: postReducer
});

export default rootReducer;

πŸ“Œ Explanation:

  • Combines userReducer and postReducer
  • The final Redux state will be:
{
user: {...},
post: {...}
}

3️⃣ redux/reducers/userReducer.js

const initialState = {
users: [],
loading: false,
error: null
};

export default function userReducer(state = initialState, action) {
switch (action.type) {
case 'FETCH_USERS_REQUEST':
return { ...state, loading: true };
case 'FETCH_USERS_SUCCESS':
return { users: action.payload, loading: false, error: null };
case 'FETCH_USERS_FAILURE':
return { ...state, loading: false, error: action.payload };
default:
return state;
}
}

4️⃣ redux/reducers/postReducer.js

const initialState = {
posts: [],
loading: false,
error: null
};

export default function postReducer(state = initialState, action) {
switch (action.type) {
case 'FETCH_POSTS_REQUEST':
return { ...state, loading: true };
case 'FETCH_POSTS_SUCCESS':
return { posts: action.payload, loading: false, error: null };
case 'FETCH_POSTS_FAILURE':
return { ...state, loading: false, error: action.payload };
default:
return state;
}
}

5️⃣ redux/actions/userActions.js

export const fetchUsers = () => {
return async (dispatch) => {
dispatch({ type: 'FETCH_USERS_REQUEST' });
try {
const res = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await res.json();
dispatch({ type: 'FETCH_USERS_SUCCESS', payload: data });
} catch (err) {
dispatch({ type: 'FETCH_USERS_FAILURE', payload: err.message });
}
};
};

6️⃣ redux/actions/postActions.js

export const fetchPosts = () => {
return async (dispatch) => {
dispatch({ type: 'FETCH_POSTS_REQUEST' });
try {
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
const data = await res.json();
dispatch({ type: 'FETCH_POSTS_SUCCESS', payload: data });
} catch (err) {
dispatch({ type: 'FETCH_POSTS_FAILURE', payload: err.message });
}
};
};

βœ… Usage in React Component (e.g., App.js)

import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchUsers } from './redux/actions/userActions';
import { fetchPosts } from './redux/actions/postActions';

function App() {
const dispatch = useDispatch();
const { users, loading: usersLoading } = useSelector(state => state.user); //
JavaScript object destructuring
const { posts, loading: postsLoading } = useSelector(state => state.post);

useEffect(() => {
dispatch(fetchUsers());
dispatch(fetchPosts());
}, [dispatch]);

return (
<div>
<h1>Users</h1>
{usersLoading ? <p>Loading Users...</p> : users.map(u => <p key={u.id}>{u.name}</p>)}

<h1>Posts</h1>
{postsLoading ? <p>Loading Posts...</p> : posts.map(p => <p key={p.id}>{p.title}</p>)}
</div>
);
}

export default App;

βœ… Conditional Dispatch in Redux (React + Redux)
Normal method to check

const handleLoad = () => {
    if (users.length === 0 && !loading) {
      dispatch(fetchUsers());  // dispatch only if not already loaded
    }
  };

Inside a Thunk (Action Creator)

export const fetchUsersIfNeeded = () => {
  return (dispatch, getState) => {
    const { users, loading } = getState().user;

    if (users.length === 0 && !loading) {
      dispatch({ type: 'FETCH_USERS_REQUEST' });

      fetch('https://jsonplaceholder.typicode.com/users')
        .then(res => res.json())
        .then(data => dispatch({ type: 'FETCH_USERS_SUCCESS', payload: data }))
        .catch(err => dispatch({ type: 'FETCH_USERS_FAILURE', payload: err }));
    }
  };
};

//  usage
dispatch(fetchUsersIfNeeded());

βœ… children Prop in React

It is a prop {this.props.children} that allow you to pass components as data to other components.

<Wrapper>
  <h1>Hello, Ved!</h1>.  // whatever place here is padded as prop.childern
</Wrapper>

//wrapper component
const Wrapper = ({ children }) => {
  return <div className="box">{children}</div>;
};

//ouput
<div class="box">
  <h1>Hello, Ved!</h1>
</div>

πŸ›  Pro Tip: children is just a prop

You can even pass it manually:

<Wrapper children={<p>Manual way</p>} />

πŸ“Œ Common Use Cases

Use CaseExample
Layout Components<Card>{content}</Card>
Modal/Dialog wrappers<Modal>{form}</Modal>
Slot-style flexibilityLike Vue’s <slot> equivalent
Libraries like React Router<Route>{component}</Route>

πŸ” React Reconciliation – Explained Simply

Reconciliation is the process by which React updates the DOM efficiently when your app’s state or props change.

πŸ” What Happens During Reconciliation?

When a component’s state or props change:

  1. React re-renders the component to produce a new virtual DOM tree.
  2. It compares this new virtual DOM with the previous one using a diffing algorithm.
  3. React calculates the minimal set of changes needed to update the actual real DOM.
  4. It applies only the necessary DOM updates (not a full re-render).

βœ… What is React.lazy()?

React.lazy() is a function that enables lazy loading of components β€” meaning the component is only loaded when it’s needed.

βœ… Why Use React.lazy()?

BenefitDescription
🐒 Lazy load componentsLoad them only when needed
πŸ“¦ Reduce bundle sizeInitial JS bundle is smaller
⚑ Faster page loadGreat for large apps or routes

πŸ”§ Syntax:

const MyComponent = React.lazy(() => import('./MyComponent'));
  • This will dynamically load MyComponent only when it’s rendered.
  • You must wrap it with <Suspense> to handle loading fallback.
// App.js
import React, { Suspense } from 'react';

const LazyAbout = React.lazy(() => import('./About'));

function App() {
  return (
    <div>
      <h1>My App</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <LazyAbout />
      </Suspense>
    </div>
  );
}

export default App;

🧠 Important Notes

  1. βœ… Must use inside a <Suspense> wrapper
  2. ⚠️ Works only for default exports (export default)
  3. 🧩 Works well with React Router and route-based code splitting

πŸš€ Route-Based Lazy Loading with React Router

import { BrowserRouter, Route, Routes } from 'react-router-dom';
const LazyHome = React.lazy(() => import('./pages/Home'));
const LazyAbout = React.lazy(() => import('./pages/About'));

function App() {
return (
<BrowserRouter>
<Suspense fallback={<p>Loading...</p>}>
<Routes>
<Route path="/" element={<LazyHome />} />
<Route path="/about" element={<LazyAbout />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}

πŸ”Œ React Portal – Render Outside the DOM Hierarchy

A Portal in React lets you render a component outside its parent DOM hierarchy, typically at the root level of the HTML document (<body>). This is especially useful for modals, tooltips, dropdowns, etc.

πŸ” Why Use Portals?

  • You want a component to visually break out of its parent container.
  • Avoid CSS issues like overflow: hidden or z-index clashes.
  • Great for overlay UIs, modals, and global components.

🧱 Syntax

ReactDOM.createPortal(child, container)
  • child: The JSX/React element to render.
  • container: A DOM node outside the React root (often in public/index.html).

πŸ›‘οΈ Error Boundaries in React

Error Boundaries are special React components that catch JavaScript errors in their child component tree during rendering, lifecycle methods, and constructors, and display a fallback UI instead of crashing the whole app.

🚨 Why Use Error Boundaries?

BenefitDescription
🧯 Prevent crashesApp won’t crash entirely on UI errors
🧩 Show fallback UIShow custom UI like “Something went wrong”
πŸ” Debugging supportCan log error details to monitoring services

⚠️ What They Catch (and Don’t)

βœ… Catches:

  • Rendering errors
  • Lifecycle errors
  • Constructor errors

❌ Doesn’t catch:

  • Event handler errors (you handle those with try/catch)
  • Async code (e.g. setTimeout)
  • Server-side rendering errors

🧱 Class-Based Error Boundary Example

import React, { Component } from 'react';

class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError(error) {
// Update state to show fallback UI
return { hasError: true };
}

componentDidCatch(error, info) {
// Log error to monitoring service
console.error("Caught error:", error, info);
}

render() {
if (this.state.hasError) {
return <h2>Something went wrong.</h2>;
}
return this.props.children;
}
}

export default ErrorBoundary;

πŸ§ͺ Usage

import ErrorBoundary from './ErrorBoundary';
import BuggyComponent from './BuggyComponent';

function App() {
return (
<div>
<h1>My App</h1>
<ErrorBoundary>
<BuggyComponent />
</ErrorBoundary>
</div>
);
}

If BuggyComponent throws an error, ErrorBoundary will catch it and render the fallback.

πŸ”₯ Buggy Component Example

function BuggyComponent() {
throw new Error("Oops! Something broke.");
return <div>This won't render</div>;
}

βš™οΈ Multiple Error Boundaries

You can wrap parts of your app separately:

<ErrorBoundary>
<ComponentA />
</ErrorBoundary>

<ErrorBoundary>
<ComponentB />
</ErrorBoundary>

Useful when different areas of the app should show different fallbacks or recover independently.

❓ Can We Use Error Boundary in Functional Components?

Not directly, because:

  • getDerivedStateFromError and componentDidCatch are lifecycle methods that only work in class components.

πŸ” Alternative: Use a custom hook with try/catch in event handlers, or a wrapper like react-error-boundary if you want to use functional style.

🧰 Popular Libraries

βœ… Can use server side rendering in react without next.js ?

Yes βœ…, you can use server-side rendering (SSR) in React without Next.js β€” by using Node.js + Express (or any backend) and manually setting up SSR using ReactDOMServer.
πŸš€ What You Need
  1. React (your components)
  2. react-dom/server (ReactDOMServer)
  3. A Node.js server (like Express)
  4. A bundler (Webpack, Vite, etc. β€” optional for client-side hydration)
/ssr-app
  /public
    index.html
  /src
    App.js
    client.js
    server.js

πŸ”Ή 1. src/App.js – React Component

import React from 'react';

const App = () => {
return <h1>Hello from Server-Side Rendered React!</h1>;
};

export default App;

πŸ”Ή 2. src/server.js – Express Server with SSR

import express from 'express';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import App from './App.js';

const app = express();
const PORT = 3000;

// Serve static files like client.js
app.use(express.static('public'));

app.get('*', (req, res) => {
const appHtml = ReactDOMServer.renderToString(<App />);

const html = `
<!DOCTYPE html>
<html>
<head>
<title>React SSR</title>
</head>
<body>
<div id="root">${appHtml}</div>
<script src="/client.js"></script> <!-- hydration -->
</body>
</html>
`;

res.send(html);
});

app.listen(PORT, () => {
console.log(`πŸš€ Server running at http://localhost:${PORT}`);
});

πŸ”Ή 3. src/client.js – Hydrate on Client Side

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.hydrateRoot(document.getElementById('root'), <App />);

πŸ”§ 4. Tooling

  • Use Webpack or Vite to build client.js and output it to /public.
  • Transpile your JSX/ES6 server code with Babel (or use esm, ts-node, etc.)

βœ… Output:

  • The HTML is generated on the server and sent to the client.
  • Then, the client-side JS takes over (hydrates) the React app.

πŸ” Advantages vs Next.js

FeatureWithout Next.js (manual)Next.js
SetupManualAuto-configured
RoutingManual (React Router)Built-in
SSRYes, with ReactDOMServerOut of the box
SEO friendlyβœ… Yesβœ… Yes
Fine-grained controlβœ… Full server controlLess flexibility (opinionated)

βš›οΈ create-react-app (CRA) – Quick Start to React Projects

create-react-app is the official tool provided by the React team to bootstrap a fully configured React application β€” without needing to manually set up Webpack, Babel, ESLint, etc.

βœ… What Does CRA Give You?

FeatureDescription
πŸ“¦ Webpack + BabelBundling & transpiling already configured
πŸ§ͺ Testing setupIncludes Jest and React Testing Library
πŸ’… CSS/SCSS supportWorks out-of-the-box with CSS & preprocessors
πŸ–Ό Asset handlingSupports images, fonts, and more via import
πŸ” ESLint + FormattingEnforced linting + Prettier-style code formatting
⚑ Dev serverComes with live-reloading dev server
πŸš€ Production buildGenerates optimized production-ready bundles

🧱 Create a New App

npx create-react-app my-app
cd my-app
npm start

This will create a folder named my-app with all required files and dependencies.

πŸš€ Common Scripts

npm start       # Run development server
npm run build # Create optimized production build
npm test # Run unit tests
npm run eject # Remove CRA abstraction (advanced use).

//πŸ›‘ Use eject only if you need full control over config (no going back).

🧠 Smart vs Dumb Components in React

FeatureSmart ComponentDumb Component
PurposeLogic, data handlingUI rendering only
Stateβœ… Yes❌ Usually stateless
Side effects (API)βœ… Yes❌ No
Reusable❌ Lessβœ… Highly reusable
ExamplesContainers, PagesButtons, Cards, Lists
Knows about Redux/Contextβœ… Often❌ Never

βœ… Good Practice

  • Separate concerns: logic in smart components, UI in dumb components.
  • Keeps code clean, testable, and scalable.

πŸ†š value vs defaultValue in React

Both value and defaultValue are used in form elements like <input>, <textarea>, and <select>, but they behave very differently depending on controlled vs uncontrolled components.

βœ… value (Controlled Component)

  • The input value is controlled by React state
  • You must use onChange to update the value
  • React has full control over the input

πŸ”§ Example:

const [name, setName] = useState('');
<input value={name} onChange={e => setName(e.target.value)} />

React updates the value based on state. Input changes won’t work unless you provide an onChange handler.

⚠️ defaultValue (Uncontrolled Component)

  • Sets the initial value only once on first render
  • After that, the value is managed by the DOM itself, not React
  • Does not require onChange, but you can still use it

πŸ”§ Example:

<input defaultValue="Ved" />

Acts like a regular HTML input with an initial value. React won’t track or update it afterward.

βœ… React Testing – Tools, Best Practices & Writing Test Cases

Testing in React ensures your components behave as expected and helps catch bugs early.

πŸ›  Best Tools for Testing React Apps

ToolPurposeRecommended
JestTest runner + assertion libraryβœ… Yes
React Testing Library (RTL)Test React components via UI behaviorβœ… Yes
Enzyme (legacy)Component testing using internal structure❌ Deprecated
CypressEnd-to-end (E2E) UI testingβœ… Yes
VitestAlternative to Jest (faster, for Vite)⚑ Optional

🧰 Recommended Setup (most common)

  • Jest + React Testing Library (RTL)

CRA (create-react-app) comes with Jest pre-installed.

To add RTL (if needed):

npm install --save-dev @testing-library/react @testing-library/jest-dom

βœ… Types of Tests

TypePurposeTools
Unit TestTest isolated functions/componentsJest + RTL
IntegrationTest multiple components togetherJest + RTL
E2E TestTest full app in browserCypress

πŸ§ͺ Writing a Simple Test Case

πŸ”Ή Component: Greeting.js

const Greeting = ({ name }) => {
return <h1>Hello, {name || 'Guest'}!</h1>;
};

export default Greeting;

πŸ”Έ Test: Greeting.test.js

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

test('renders greeting with name', () => {
render(<Greeting name="Ved" />);
expect(screen.getByText('Hello, Ved!')).toBeInTheDocument();
});

test('renders greeting with default', () => {
render(<Greeting />);
expect(screen.getByText('Hello, Guest!')).toBeInTheDocument();
});

🧠 Common React Test Utilities

FunctionPurpose
render()Render a component into virtual DOM
screen.getByText()Query rendered DOM
fireEvent.click()Simulate user events
expect(...).toBe...Assert result
waitFor()Wait for async updates

πŸ”₯ Testing Form Inputs

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

test('updates input value', () => {
render(<Form />);
const input = screen.getByPlaceholderText('Enter name');
fireEvent.change(input, { target: { value: 'Ved' } });
expect(input.value).toBe('Ved');
});

πŸ“¦ Example Folder Structure

/src
/components
Greeting.js
Greeting.test.js
Form.js
Form.test.js

πŸ” Running Tests

npm test

This will run in watch mode (re-runs affected tests on save).

πŸ’‘ Best Practices

βœ… Use data-testid or accessible labels (avoid className selectors)
βœ… Test behavior, not internal implementation
βœ… Keep tests fast and isolated
βœ… Write both positive and negative cases
βœ… Use jest.fn() to mock functions

❓ Bonus: When to Use Cypress?

Use Cypress when you want to test:

  • Navigation
  • Actual browser behavior
  • Integration between pages/components

πŸ§ͺ Jest Hooks/Lifecycle: Setup & Teardown – beforeEach, afterEach, beforeAll, afterAll

Jest provides global lifecycle hooks to run code before and after tests β€” perfect for setup, teardown, or shared logic.

describe('Math tests', () => {
  beforeAll(() => {
    console.log('πŸ”§ Setup before all tests');
  });

  afterAll(() => {
    console.log('🧹 Cleanup after all tests');
  });

  beforeEach(() => {
    console.log('πŸ“¦ Setup before each test');
  });

  afterEach(() => {
    console.log('🧽 Cleanup after each test');
  });

  test('adds numbers', () => {
    expect(1 + 2).toBe(3);
  });

  test('multiplies numbers', () => {
    expect(2 * 2).toBe(4);
  });
});

Jasmine: it s also a testing framework (BDD) but less common, and not good as compare to Jest.

πŸ” Callback vs πŸ”„ Promise vs ⚑ Async/Await in JavaScript

🧩 1. Callback (Legacy before ES6)

A function passed as an argument to another function to be executed later.

πŸ“Œ Example:

function greetUser(name, callback) {
console.log(`Hello, ${name}`);
callback();
}

function sayBye() {
console.log('Goodbye!');
}

greetUser('Ved', sayBye);

⚠️ Drawback:

  • Leads to callback hell when nesting too deeply
  • Difficult to read, debug, and manage

πŸ”— 2. Promise (ES6)

A cleaner way to handle async operations, providing .then() and .catch() methods.

πŸ“Œ Example:

function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Data loaded');
}, 1000);
});
}

fetchData()
.then(data => console.log(data))
.catch(error => console.error(error));

βœ… Benefit:

  • Chainable, cleaner than nested callbacks
  • Easier to handle errors using .catch()

βœ… A Promise can return:

Return TypeWhat It Means
resolve(value)The operation succeeded, and value is the result
reject(error)The operation failed, and error is the reason
return another promiseThe outer promise will adopt the inner promise’s state
NothingIt will be treated as undefined return when resolved. r
resolve(); // Same as resolve(undefined)

⚑ 3. Async/Await (ES8 (ES2017))

A syntax sugar built on top of Promises that makes async code look synchronous.

πŸ“Œ Example:

async function loadData() {
try {
const data = await fetchData();
console.log(data);
} catch (error) {
console.error(error);
}
}

loadData();

βœ… Benefit:

  • Most readable and maintainable
  • Use try/catch for error handling
  • Clean sequential logic

🌐 Fetch Multiple URLs in React (or JavaScript)

To fetch multiple URLs in React (or any JS code), you typically use:

  • Promise.all() – to wait for all requests to finish
  • async/await – to handle them cleanly

βœ… Basic Example – Fetch Multiple APIs

const fetchMultipleData = async () => {
const urls = [
'https://api.example.com/users',
'https://api.example.com/posts',
'https://api.example.com/comments',
];

try {
const responses = await Promise.all(urls.map(url => fetch(url)));
const data = await Promise.all(responses.map(res => res.json()));
console.log(data); // [usersData, postsData, commentsData]
} catch (err) {
console.error('Error fetching:', err);
}
};

🧩 React Component Example

import React, { useEffect, useState } from 'react';

const MultiFetch = () => {
const [users, setUsers] = useState([]);
const [posts, setPosts] = useState([]);

useEffect(() => {
const fetchData = async () => {
const [userRes, postRes] = await Promise.all([
fetch('https://jsonplaceholder.typicode.com/users'),
fetch('https://jsonplaceholder.typicode.com/posts')
]);
const [userData, postData] = await Promise.all([
userRes.json(),
postRes.json()
]);
setUsers(userData);
setPosts(postData);
};

fetchData();
}, []);

return (
<div>
<h2>Users: {users.length}</h2>
<h2>Posts: {posts.length}</h2>
</div>
);
};

export default MultiFetch;

βœ… Handle Cascading failure case

When fetching multiple URLs, it’s crucial to handle both scenarios:

  1. βœ… All requests succeed
  2. ❌ One or more requests fail

βœ… Option 1: Use Promise.all – Fast but fails on any error

try {
const responses = await Promise.all([
fetch('/api/one'),
fetch('/api/two'),
fetch('/api/three'),
]);
const data = await Promise.all(responses.map(res => res.json()));
console.log('All passed βœ…', data);
} catch (error) {
console.error('At least one request failed ❌:', error);
}

❗ Limitation:

  • If even one request fails (e.g., network error or 500), the entire block fails.
  • No partial success.

βœ… Option 2: Use Promise.allSettled – Safer for mixed results

const urls = ['/api/one', '/api/two', '/api/three'];

const results = await Promise.allSettled(urls.map(url => fetch(url)));

const successful = [];
const failed = [];

for (let i = 0; i < results.length; i++) {
  if (results[i].status === 'fulfilled') {
    const json = await results[i].value.json();
    successful.push({ url: urls[i], data: json });
  } else {
    failed.push({ url: urls[i], error: results[i].reason });
  }
}

if (failed.length === 0) {
  console.log('πŸŽ‰ All requests succeeded', successful);
} else {
  console.warn('⚠️ Some requests failed', failed);
  console.log('βœ… Successful responses', successful);
}

πŸ”„ yield in JavaScript

🧠 What is yield?

yield is a special keyword used inside generator functions to pause the function execution and return a value.

It allows building iterators, lazy sequences, and asynchronous flows.

πŸ”§ Syntax

function* generatorName() {
yield value1;
yield value2;
}
  • function* declares a generator function
  • yield pauses execution and returns a value
  • Calling the generator returns an iterator object

βœ… Basic Example

function* colors() {
yield 'red';
yield 'green';
yield 'blue';
}

const gen = colors();

console.log(gen.next()); // { value: 'red', done: false }
console.log(gen.next()); // { value: 'green', done: false }
console.log(gen.next()); // { value: 'blue', done: false }
console.log(gen.next()); // { value: undefined, done: true }

🧩 How yield Works

ConceptExplanation
yieldPauses the generator and returns a value
next()Resumes execution from where it was paused
Multiple yieldsActs like a step-by-step iterator
Can accept inputnext(value) passes data back into the generator

πŸ“₯ yield with Input (Two-Way Communication)

function* greet() {
const name = yield "What is your name?";
yield `Hello, ${name}!`;
}

const g = greet();

console.log(g.next().value); // "What is your name?"
console.log(g.next('Ved').value); // "Hello, Ved!"

Limitation: Yields can only be called directly from the generator function that contain it. It can not be called from the nested function or from callbacks.

βœ… What is Redux Saga in React?

Redux-Saga is a middleware library used in Redux applications to handle side effects like:

  • API calls
  • Delays or retries
  • Accessing browser cache, storage, etc.

Instead of using thunks (functions inside actions), Redux-Saga uses generators and yield to handle async code in a more declarative and testable way.

🧠 Why Use Redux-Saga?

Problem in ReduxHow Redux-Saga Helps
Redux is synchronousSaga lets you handle async logic
Async code in actions (thunk) becomes messySaga uses generator-based workflows
Difficult to test thunksSaga effects (call, put, etc.) are testable

πŸ”§ Basic Redux-Saga Flow

  1. UI Dispatches an action (FETCH_USER_REQUEST)
  2. Saga intercepts the action
  3. Saga runs side-effect (e.g., API call)
  4. Saga dispatches success or error actions

βš™ Key Concepts in Redux-Saga

ConceptDescription
sagaA generator function that performs async tasks
takeEveryListens for every matching action and runs a worker saga
callInvokes a function (like an API call) and waits for result
putDispatches an action
takeLatestOnly runs the latest call (cancels older ones)

πŸ“ Folder Structure

/redux-saga-example/
β”‚
β”œβ”€β”€ /src/
β”‚ β”œβ”€β”€ /redux/
β”‚ β”‚ β”œβ”€β”€ store.js
β”‚ β”‚ β”œβ”€β”€ rootReducer.js
β”‚ β”‚ β”œβ”€β”€ rootSaga.js
β”‚ β”‚ β”œβ”€β”€ /user/
β”‚ β”‚ β”‚ β”œβ”€β”€ userActions.js
β”‚ β”‚ β”‚ β”œβ”€β”€ userReducer.js
β”‚ β”‚ β”‚ β”œβ”€β”€ userSaga.js
β”‚
β”œβ”€β”€ /components/
β”‚ β”œβ”€β”€ UserComponent.jsx
β”‚
β”œβ”€β”€ App.js
β”œβ”€β”€ index.js

🧩 1. userActions.js

// src/redux/user/userActions.js
export const FETCH_USER_REQUEST = 'FETCH_USER_REQUEST';
export const FETCH_USER_SUCCESS = 'FETCH_USER_SUCCESS';
export const FETCH_USER_FAILURE = 'FETCH_USER_FAILURE';

export const fetchUserRequest = (id) => ({ type: FETCH_USER_REQUEST, payload: id });

🧠 2. userReducer.js

// src/redux/user/userReducer.js
import { FETCH_USER_REQUEST, FETCH_USER_SUCCESS, FETCH_USER_FAILURE } from './userActions';

const initialState = {
user: null,
loading: false,
error: null,
};

const userReducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_USER_REQUEST:
return { ...state, loading: true };
case FETCH_USER_SUCCESS:
return { ...state, user: action.payload, loading: false };
case FETCH_USER_FAILURE:
return { ...state, error: action.error, loading: false };
default:
return state;
}
};

export default userReducer;

βš™οΈ 3. userSaga.js

// src/redux/user/userSaga.js
import { call, put, takeEvery } from 'redux-saga/effects';
import axios from 'axios';
import { FETCH_USER_REQUEST } from './userActions';

function* fetchUserWorker(action) {
try {
const response = yield call(axios.get, `https://jsonplaceholder.typicode.com/users/${action.payload}`);
yield put({ type: 'FETCH_USER_SUCCESS', payload: response.data });
} catch (e) {
yield put({ type: 'FETCH_USER_FAILURE', error: e.message });
}
}

export default function* userSaga() {
yield takeEvery(FETCH_USER_REQUEST, fetchUserWorker);
}

πŸ”— 4. rootReducer.js

// src/redux/rootReducer.js
import { combineReducers } from 'redux';
import userReducer from './user/userReducer';

const rootReducer = combineReducers({
user: userReducer,
});

export default rootReducer;

πŸ”— 5. rootSaga.js

// src/redux/rootSaga.js
import { all } from 'redux-saga/effects';
import userSaga from './user/userSaga';

export default function* rootSaga() {
yield all([userSaga()]);
}

πŸ— 6. store.js

// src/redux/store.js
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootReducer from './rootReducer';
import rootSaga from './rootSaga';

const sagaMiddleware = createSagaMiddleware();

const store = createStore(
rootReducer,
applyMiddleware(sagaMiddleware)
);

sagaMiddleware.run(rootSaga);

export default store;

🧱 7. UserComponent.jsx

// src/components/UserComponent.jsx
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchUserRequest } from '../redux/user/userActions';

const UserComponent = () => {
const dispatch = useDispatch();
const { user, loading, error } = useSelector((state) => state.user);

useEffect(() => {
dispatch(fetchUserRequest(1));
}, [dispatch]);

if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return user ? <div>User: {user.name}</div> : null;
};

export default UserComponent;

πŸš€ 8. App.js

// src/App.js
import React from 'react';
import UserComponent from './components/UserComponent';

const App = () => <UserComponent />;

export default App;

πŸ›  9. index.js

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './redux/store';
import App from './App';

ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);

βœ… Summary – File Relations

FilePurpose
userActions.jsAction constants & creators
userReducer.jsHandles state changes
userSaga.jsWatches actions, handles API calls
rootReducer.jsCombines all reducers
rootSaga.jsCombines all sagas
store.jsConfigures Redux store & middleware
UserComponent.jsxDispatches action, reads Redux state
App.js, index.jsStarts the app and wraps with Provider

🎯 Common Redux-Saga Effects

EffectPurpose
callCall a function (e.g., API) and wait for result
putDispatch a Redux action
takeWait for a specific action to occur
takeEveryRun saga for every matching action
takeLatestRun only the latest if rapid actions fired
forkStart a non-blocking task
spawnLike fork, but detached from parent
allRun multiple effects in parallel
delayWait for a specific time (like sleep)
selectAccess the current Redux store state
cancelCancel a running task
raceCompete multiple effects; only one wins

🧼 What is a Pure Function?

A pure function is a function that:

  1. Always returns the same output for the same input
  2. Has no side effects (doesn’t modify external state)

A side effect is anything a function does other than returning a result.

πŸ”₯ Examples of Side Effects:

Side Effect ExampleWhat Happens
Logging to consoleChanges developer console state
Modifying a global variableAlters external data
Writing to a file / databaseChanges outside world
Making an API callAffects network, outside your app
Updating the DOMChanges the browser UI
Setting a timer (setTimeout)Triggers something asynchronously

πŸ’£ What is an Impure Function?

An impure function:

  • Might return different outputs for the same input
  • Produces side effects

🧩 What is Currying?

Currying is the process of transforming a function with multiple arguments into a sequence of functions, each taking a single argument.

It turns: f(a, b, c) β†’ f(a)(b)(c)

πŸ”Έ Normal Function:

function add(a, b) {
return a + b;
}
add(2, 3); // 5

πŸ”Έ Curried Version:

function curriedAdd(a) {
return function (b) {
return a + b;
};
}
curriedAdd(2)(3); // 5

πŸ”§ Using ES6 Arrow Functions

const curriedMultiply = a => b => a * b;
curriedMultiply(4)(5); // 20

πŸ“¦ Webpack + Sass (SCSS) Setup From Scratch

This guide sets up a modern front-end development environment using:

βœ… Webpack (bundler)
βœ… Babel (for ES6+)
βœ… Sass (CSS preprocessor)
βœ… Dev server with live reloading

🧱 1. πŸ“ Folder Structure

my-app/
β”œβ”€β”€ dist/
β”‚ └── index.html
β”œβ”€β”€ src/
β”‚ β”œβ”€β”€ index.js
β”‚ └── style.scss
β”œβ”€β”€ package.json
β”œβ”€β”€ webpack.config.js
β”œβ”€β”€ .babelrc

βš™οΈ 2. πŸ”§ Initialize Project

mkdir my-app && cd my-app
npm init -y

🧩 3. πŸ“¦ Install Dependencies

➀ Webpack & Babel

npm install --save-dev webpack webpack-cli webpack-dev-server
npm install --save-dev @babel/core @babel/preset-env babel-loader

➀ Sass & Loaders

npm install --save-dev sass sass-loader css-loader style-loader

πŸ”§ 4. βš™οΈ Webpack Config

πŸ”Έ webpack.config.js

const path = require('path');

module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
devServer: {
static: './dist',
hot: true,
port: 3000,
open: true,
},
module: {
rules: [
{
test: /\.js$/, // JS
exclude: /node_modules/,
use: 'babel-loader',
},
{
test: /\.scss$/, // Sass
use: ['style-loader', 'css-loader', 'sass-loader'],
},
],
},
};

πŸ”§ 5. 🧠 Babel Configuration

πŸ”Έ .babelrc

{
"presets": ["@babel/preset-env"]
}

✍️ 6. Create Files

πŸ”Έ src/index.js

import './style.scss';
console.log('Webpack + Sass working!');

πŸ”Έ src/style.scss

$color: #2ecc71;

body {
background: $color;
font-family: Arial, sans-serif;
padding: 2rem;
color: white;
}

πŸ”Έ dist/index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Webpack Sass Setup</title>
</head>
<body>
<h1>Hello Webpack + Sass!</h1>
<script src="bundle.js"></script>
</body>
</html>

πŸ§ͺ 7. Add Scripts in package.json

"scripts": {
"start": "webpack serve",
"build": "webpack"
}

πŸš€ 8. Start Development Server

npm start

Visit πŸ‘‰ http://localhost:3000

βš™οΈ Common React Patterns

  1. Container & Presentational
    • Separate logic (container) from UI (presentational)
  2. Higher-Order Component (HOC)
    • Wrap a component to add extra logic (e.g., withAuth(Component))
  3. Render Props
    • Share logic using a render or children function
  4. Controlled vs Uncontrolled Components
    • Controlled: uses React state
    • Uncontrolled: uses refs
  5. Compound Components
    • Components share internal state via context (e.g., <Tabs> with <Tabs.Tab>)
  6. Custom Hooks
    • Reusable logic using useState, useEffect, etc.
  7. Context API
    • Avoid prop drilling; share global data like theme/auth
  8. State Reducer Pattern
    • Let parent override child behavior via reducer
  9. Children-as-a-Prop
    • Pass JSX in children for flexible layouts
  10. Functional State Update
  • setCount(prev => prev + 1) to update based on previous state

βš”οΈ React API (REST) vs GraphQL API

FeatureREST API (React uses fetch/axios)GraphQL API
Request TypeMultiple endpoints (e.g., /users, /posts)Single endpoint (/graphql)
Data FetchingFixed structure (server decides)Flexible (client decides what to get)
Over-fetchingYes (gets extra data)❌ Avoided (fetch only needed fields)
Under-fetchingMay need multiple requests❌ Avoided (combine in one query)
VersioningNeeds new versions (v1, v2)No versioning needed
Batch RequestsNeeds custom handling or parallel fetchBuilt-in with nested queries
ErrorsPer request/endpointField-level error support
ToolsFetch, Axios, React QueryApollo Client, Relay
CachingManual or with tools (React Query)Apollo has built-in cache
SchemaOptional/openStrongly typed schema

πŸ”§ Example

βœ… REST in React

useEffect(() => {
fetch('/api/users/1')
.then(res => res.json())
.then(data => setUser(data));
}, []);

βœ… GraphQL in React (Apollo)

const GET_USER = gql`
query GetUser {
user(id: 1) {
name
email
}
}
`;

const { data, loading } = useQuery(GET_USER);

πŸ” Normal Function vs Arrow Function

FeatureNormal FunctionArrow Function
Syntaxfunction name() {}const name = () => {}
this BindingDynamic (this depends on how it’s called)Lexical (this is inherited from parent scope)
Arguments Objectβœ… Has arguments object❌ No arguments object
Constructors (new)βœ… Can be used as constructor❌ Cannot be used with new
Methods in Classβœ… Common for defining methods⚠ Not recommended for methods
Implicit Return❌ Must use return keywordβœ… Auto-return if one expression (no {})
Hoistingβœ… Hoisted❌ Not hoisted

βœ… Example Comparison

πŸ”Ή Normal Function

function add(a, b) {
return a + b;
}

πŸ”Ή Arrow Function

const add = (a, b) => a + b;

πŸ” this Binding Example

const obj = {
count: 10,
normal: function () {
console.log(this.count); // 10 βœ…
},
arrow: () => {
console.log(this.count); // undefined ❌ (lexical this)
},
};

🧠 When to Use What?

Use Normal FunctionUse Arrow Function
As methods in classes/objectsFor short callbacks & functional code
When this needs to be dynamically boundWhen using lexical this is desired
When using arguments objectFor concise, one-line expressions

Similar Posts