Fundamentals
React Application Lifecycle
There are four different phases in the lifecycle of React component. They are:
- Initialization: During this phase, React component will prepare by setting up the default props and initial state for the upcoming tough journey.
- Mounting: Mounting refers to putting the elements into the browser DOM. Since React uses VirtualDOM, the entire browser DOM which has been currently rendered would not be refreshed. This phase includes the lifecycle methods
componentWillMount
andcomponentDidMount
.
- Updating: In this phase, a component will be updated when there is a change in the state or props of a component. This phase will have lifecycle methods like
componentWillUpdate
,shouldComponentUpdate
,render
, andcomponentDidUpdate
.
- Unmounting: In this last phase of the component lifecycle, the component will be removed from the DOM or will be unmounted from the browser DOM. This phase will have the lifecycle method named
componentWillUnmount
.

JSX?
JSX stands for JavaScript XML. It allows us to write HTML inside JavaScript and place them in the DOM without using functions like appendChild( ) or createElement( ).
As stated in the official docs of React, JSX provides syntactic sugar for React.createElement( ) function.
Note- We can create react applications without using JSX as well.
Virtual DOM
As stated by the react team, virtual DOM is a concept where a virtual representation of the real DOM is kept inside the memory and is synced with the real DOM by a library such as ReactDOM.


React State
Every component in react has a built-in state object, which contains all the property values that belong to that component.In other words, the state object controls the behaviour of a component. Any change in the property values of the state object leads to the re-rendering of the component.
Note- State object is not available in functional components but, we can use React Hooks to add state to a functional component.
How to declare a state object?
Example:
class Car extends React.Component{ constructor(props){ super(props); this.state = { brand: "BMW", color: "black" } } }
How to use and update the state object?
class Car extends React.Component { constructor(props) { super(props); this.state = { brand: "BMW", color: "Black" }; } changeColor() { this.setState(prevState => { return { color: "Red" }; }); } render() { return ( <div> <button onClick={() => this.changeColor()}>Change Color</button> <p>{this.state.color}</p> </div> ); } }
React Props
Every React component accepts a single object argument called props (which stands for “properties”). These props can be passed to a component using HTML attributes and the component accepts these props as an argument.Using props, we can pass data from one component to another.
While rendering a component, we can pass the props as an HTML attribute:
<Car brand="Mercedes"/>
In Class component:
class Car extends React.Component { constructor(props) { super(props); this.state = { brand: this.props.brand, color: "Black" }; } }
In Functional component:
function Car(props) { let [brand, setBrand] = useState(props.brand); }
Note- Props are read-only. They cannot be manipulated or changed inside a component.
Error boundary
Introduced in version 16 of React, Error boundaries provide a way for us to catch errors that occur in the render phase.
Any component which uses one of the following lifecycle methods is considered an error boundary.
In what places can an error boundary detect an error?
- Render phase
- Inside a lifecycle method
- Inside the constructor
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, errorInfo) { logErrorToMyService(error, errorInfo); } render() { if (this.state.hasError) { return <h4>Something went wrong</h4> } return this.props.children; } }
In the code above, getDerivedStateFromError function renders the fallback UI interface when the render method has an error.
componentDidCatch logs the error information to an error tracking service.
Now with the error boundary, we can render the CounterComponent in the following way:
<ErrorBoundary> <CounterComponent/> </ErrorBoundary>
React Hooks
React Hooks are the built-in functions that permit developers for using the state and lifecycle methods within React components. These are newly added features made available in React 16.8 version.
There are 2 rules which must be followed while you code with Hooks:
- React Hooks must be called only at the top level. It is not allowed to call them inside the nested functions, loops, or conditions.
- It is allowed to call the Hooks only from the React Function Components.
useState()
: Its a built-in React Hook that allows you for having state variables in functional components. It should be used when the DOM has something that is dynamically manipulating/controlling.
... const [count, setCounter] = useState(0); const [otherStuffs, setOtherStuffs] = useState(...); ... const setCount = () => { setCounter(count + 1); setOtherStuffs(...); ... };
useEffect()
: It is used to perform side effects in functional components—operations that occur outside the main rendering process. These side effects can include tasks like fetching data from APIs, directly manipulating the DOM, setting up event listeners or subscriptions, and cleaning up resources when a component unmounts.- It runs after the component renders, meaning the DOM is updated before the effect runs.
- It takes two arguments:
- A callback function containing the side effect logic.
- An optional dependency array that controls when the effect should re-run.
- If you provide a dependency array (
[dependencies]
), React re-runs the effect only when one of those dependencies changes. - If the array is empty (
[]
), the effect runs only once after the initial render (similar tocomponentDidMount
). - If no dependency array is provided, the effect runs after every render.
- The optional return function inside
useEffect
is a cleanup function, useful for cleaning resources such as timers, subscriptions, or event listeners before the effect re-runs or when the component unmounts. useEffect
can have multiple instances in a component, each handling different side effects independently.- You should include all variables used inside the
useEffect
callback that come from the component scope in the dependency array to avoid stale closures and ensure correct behavior.
useEffect(() => { // Side effect code here return () => { // Optional cleanup code here (e.g., remove event listeners) }; }, [dependencies]);
-
useCallback()
: It is used to memoize a callback function, meaning it caches the function instance so that the same function reference is returned between component renders unless its dependencies change. This helps prevent unnecessary re-creation of the function on every render, which is beneficial for optimizing performance, especially when passing callbacks to child components or using them as dependencies in other hooks likeuseEffect
. - Syntax:
- How it works:
- On the initial render, it creates and returns the callback function.
- On subsequent renders, if dependencies have not changed, it returns the same function instance from the previous render.
- If any dependency changes, a new function instance is created and returned.
- Why use
useCallback
: - Prevents unnecessary re-renders of child components that rely on function props by stabilizing function references.
- Improves performance in scenarios such as rendering lists where callbacks are passed repeatedly.
- Helps avoid unwanted re-execution of effects when functions are dependencies.
- Useful in preserving function references in custom hooks
const memoizedCallback = useCallback(() => { // Your callback logic here }, [dependencies]);
It takes two arguments: the callback function to memoize and an array of dependencies. The memoized function only updates if a dependency changes.
useRef()
: It is used to persist a mutable value across component renders without causing re-renders when the value changes. It returns a plain JavaScript object with a single property,current
, which holds the mutable value.- Basic usage:
const ref = useRef(initialValue);
- Common use cases:
- Accessing DOM elements: By attaching a ref object to a JSX element via the
ref
attribute,ref.current
will point to the corresponding DOM node after rendering, allowing direct DOM manipulation like focusing an input. - Storing mutable values that do not trigger re-render: Useful for storing things like timers, previous state values, or any mutable data you want to keep between renders without causing updates.
- Tracking previous state or props: You can store the previous value for comparison purposes.
- Characteristics:
- Changing
ref.current
does not trigger a component re-render. - The
ref
object itself is stable; the same object is returned on every render. - Typically used for imperative DOM manipulation or holding mutable values.
- When to use
useRef
rather thanuseState
:
Here,
ref
is an object with a .current
property initially set to initialValue
. This value can be read or mutated directly, and it will persist between renders without triggering re-renders.const inputRef = useRef(null); useEffect(() => { inputRef.current.focus(); }, []); return <input ref={inputRef} />;
const countRef = useRef(0); countRef.current = someNewValue; // Updates without re-rendering
Use
useRef
when you want to persist some value without it causing a UI update. For UI-changing values, useState
is preferreduseContext()
: It is used for creating common data that is to be accessed by the components hierarchy without having to pass the props down to each level.
useReducer()
: It is used when there is a complex state logic that is having several sub-values or when the upcoming state is dependent on the previous state. It will also enable you to optimization of component performance that will trigger deeper updates as it is permitted to pass the dispatch down instead of callbacks.
useMemo
()
: This will be used for recomputing the memoized value when there is a change in one of the dependencies. This optimization will help for avoiding expensive calculations on each render.
useImperativeHandle()
: It will enable modifying the instance that will be passed with the ref object.
useDebugValue()
: It is used for displaying a label for custom hooks in React DevTools.
useLayoutEffect()
: It is used for the reading layout from the DOM and re-rendering synchronously.
Custom Hooks
A Custom Hook is a function in Javascript whose name begins with ‘use’ and which calls other hooks. It is a part of React v16.8 hook update and permits you for reusing the stateful logic without any need for component hierarchy restructuring.
In almost all of the cases, custom hooks are considered to be sufficient for replacing render props and HoCs (Higher-Order components) and reducing the amount of nesting required. Custom Hooks will allow you for avoiding multiple layers of abstraction or wrapper hell that might come along with Render Props and HoCs.
The disadvantage of Custom Hooks is it cannot be used inside of the classes.
Higher Order Components
Simply put, Higher-Order Component(HOC) is a function that takes in a component and returns a new component.
While developing React applications, we might develop components that are quite similar to each other with minute differences. In most cases, developing similar components might not be an issue but, while developing larger applications we need to keep our code DRY, therefore, we want an abstraction that allows us to define this logic in a single place and share it across components. HOC allows us to create that abstraction.
QnA
What are the differences between controlled and uncontrolled components?
Controlled and uncontrolled components are just different approaches to handling input from elements in react.
Feature | Uncontrolled | Controlled | Name attrs |
One-time value retrieval (e.g. on submit) | ✔️ | ✔️ | ✔️ |
Validating on submit | ✔️ | ✔️ | ✔️ |
Field-level Validation | ❌ | ✔️ | ✔️ |
Conditionally disabling submit button | ❌ | ✔️ | ✔️ |
Enforcing input format | ❌ | ✔️ | ✔️ |
several inputs for one piece of data | ❌ | ✔️ | ✔️ |
dynamic inputs | ❌ | ✔️ | 🤔 |
- Controlled component: In a controlled component, the value of the input element is controlled by React. We store the state of the input element inside the code, and by using event-based callbacks, any changes made to the input element will be reflected in the code as well.
function FormValidation(props) { let [inputValue, setInputValue] = useState(""); let updateInput = e => { setInputValue(e.target.value); }; return ( <div> <form> <input type="text" value={inputValue} onChange={updateInput} /> </form> </div> ); }
- Uncontrolled component: In an uncontrolled component, the value of the input element is handled by the DOM itself. Input elements inside uncontrolled components work just like normal HTML input form elements.The state of the input element is handled by the DOM. Whenever the value of the input element is changed, event-based callbacks are not called. Basically, react does not perform any action when there are changes made to the input element.
function FormValidation(props) { let inputValue = React.createRef(); let handleSubmit = e => { alert(`Input value: ${inputValue.current.value}`); e.preventDefault(); }; return ( <div> <form onSubmit={handleSubmit}> <input type="text" ref={inputValue} /> <button type="submit">Submit</button> </form> </div> ); }
Differentiate React Hooks vs Classes.
React Hooks | Classes |
It is used in functional components of React. | It is used in class-based components of React. |
It will not require a declaration of any kind of constructor. | It is necessary to declare the constructor inside the class component. |
It does not require the use of this keyword in state declaration or modification. | Keyword this will be used in state declaration (this.state ) and in modification (this.setState() ). |
It is easier to use because of the useState functionality. | No specific function is available for helping us to access the state and its corresponding setState variable. |
React Hooks can be helpful in implementing Redux and context API. | Because of the long setup of state declarations, class states are generally not preferred. |
