Download as pdf or txt
Download as pdf or txt
You are on page 1of 16

React Hooks

React hooks are a feature introduced in React 16.8 that allow you to use state
and other React features without writing a class component. Before hooks,
state and lifecycle methods were exclusively available to class components.
With hooks, these capabilities became accessible in function components as
well, enabling developers to write more concise and readable components.

1. useEffect

`useEffect` is used to perform side effects (like data fetching, subscriptions,


manual DOM manipulations, etc.) in functional components. It can replace
`componentDidMount`, `componentDidUpdate`, and
`componentWillUnmount` lifecycles in class components.

example of `useEffect`:

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

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

useEffect(() => {
document.title = `You clicked ${count} times`;

return () => {
This is the cleanup function. It's equivalent to componentWillUnmount in
class components.
In this case, it doesn't do anything, but you might use it to clear timers,
cancel network requests, etc.
};
});

return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
export default Example;

2. `useRef`

`useRef` returns a mutable ref object whose `.current` property is initialized


with the passed argument (`initialValue`). The returned object will persist for
the full lifetime of the component.

It's commonly used to access the DOM directly, but it can also be used to keep
a mutable reference to any value without re-rendering the component.

Example:

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


function TextInputWithFocusButton() {
const inputEl = useRef(null);
const [value, setValue] = useState("");

const onButtonClick = () => {


`current` points to the mounted text input element
inputEl.current.focus();
};

return (
<>
<input
ref={inputEl}
value={value}
onChange={e => setValue(e.target.value)}
/>
<button onClick={onButtonClick}>
Focus the input
</button>
</>
);
}

export default TextInputWithFocusButton;


The `useRef` hook is versatile and can be used for various purposes beyond just
referencing DOM elements. examples:

1. Storing the Previous State/Props

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

function PreviousValueComponent() {
const [count, setCount] = useState(0);
const prevCountRef = useRef();

useEffect(() => {
prevCountRef.current = count;
}, [count]);

return (
<div>
<h1>Now: {count}, Before: {prevCountRef.current}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default PreviousValueComponent;
2. Tracking IsMounted to Prevent State Updates on Unmounted Components

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

function TimerComponent() {
const [seconds, setSeconds] = useState(0);
const isMountedRef = useRef(true);

useEffect(() => {
const interval = setInterval(() => {
if (isMountedRef.current) {
setSeconds((prevSeconds) => prevSeconds + 1);
}
}, 1000);

return () => {
isMountedRef.current = false;
clearInterval(interval);
};
}, []);

return <div>Elapsed time: {seconds} seconds</div>;


}
3. Using Refs to Store Interval or Timeout IDs for Cleanup

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

function IntervalComponent() {
const [count, setCount] = useState(0);
const intervalIdRef = useRef(null);

useEffect(() => {
intervalIdRef.current = setInterval(() => {
setCount((prevCount) => prevCount + 1);
}, 1000);

return () => {
clearInterval(intervalIdRef.current);
};
}, []);

const stopInterval = () => {


clearInterval(intervalIdRef.current);
};

return (
<div>
<h1>{count}</h1>
<button onClick={stopInterval}>Stop Counting</button>
</div>
);
}

4. Using Refs for Callback Functions

This is a common pattern when the callback function needs to persist without
being recreated every render.

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

function CallbackComponent() {
const [count, setCount] = useState(0);
const callbackRef = useRef(null);

callbackRef.current = () => {
alert("Count is: " + count);
};

useEffect(() => {
const timer = setTimeout(() => {
callbackRef.current();
}, 5000); Alert count value after 5 seconds
return () => clearTimeout(timer);
}, [count]); Re-run effect if count changes

return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}

The mutable nature of the `ref` object makes it ideal for storing values or
references that persist across renders without causing re-renders.

3. `useMemo`

`useMemo` will return a memoized version of the value/function that only re-
computes if one of the dependencies has changed. This can be useful for
optimization, especially in cases where re-computation is expensive.

Example:
import React, { useState, useMemo } from 'react';
function ExpensiveComputationComponent({ computation, data }) {
const computedValue = useMemo(() => {
Imagine this computation is more expensive
return computation(data);
}, [computation, data]);

return <div>{computedValue}</div>;
}

function App() {
const [number, setNumber] = useState(0);

const doubleNumber = useMemo(() => {


return number 2;
}, [number]);

return (
<div>
<button onClick={() => setNumber(number + 1)}>Increment</button>
<ExpensiveComputationComponent computation={(num) => num 2}
data={number} />
<p>Double: {doubleNumber}</p>
</div>
);
}

In this example, the computation `(num) => num 2` is "expensive", so we use


`useMemo` to only recompute `doubleNumber` when `number` changes.
React component life cycle:
In React, component lifecycle methods are special methods that automatically
get called as your component achieves certain milestones. Lifecycle methods
provide you the ability to hook into React's view rendering process at different
points.

Starting with React 16.3, the team introduced new lifecycle methods and also
deprecated some of the old ones to make asynchronous rendering more safe.
Here's a look at the "updating" phase lifecycle methods:

Updating Lifecycle Hooks

The "updating" phase is triggered every time there's a change in props or state
that might lead to a re-render of the component.

1. `static getDerivedStateFromProps(props, state)`

- When it's called: This method is called right before every render, both for the
initial mount and all re-renders.
- Purpose: To allow the component to update its state as the result of changes
in props.
- Usage: It should return an object to update the state, or `null` to update
nothing.

2. `shouldComponentUpdate(nextProps, nextState)`

- When it's called: Before rendering, after `getDerivedStateFromProps`.


- Purpose: To let React know if the component's output is affected by the
current change in state or props. It's a performance optimization method.
- Usage: Return `false` if you're certain the update doesn't require a re-render,
`true` otherwise.

3. `render()`

- When it's called: This method is required and is called during the updating
and mounting phase.
- Purpose: It examines this.props and this.state and should return one of the
following types: React elements, Arrays and fragments, Portals, String and
numbers, Booleans or null.

4. `getSnapshotBeforeUpdate(prevProps, prevState)`

- When it's called: Right before the most recently rendered output is
committed to the DOM. It enables capturing some information from the DOM
(like scroll position) before it's potentially changed.
- Purpose: Useful when you need to capture some information from the DOM
before it's changed (e.g., the scroll position).
- Usage: Whatever value you return will be passed as the third parameter to
`componentDidUpdate`.

5. `componentDidUpdate(prevProps, prevState, snapshot)`

- When it's called: Immediately after updating (re-rendering).


- Purpose: To allow side effects (like AJAX requests) or manual DOM
manipulations after an update.
- Usage: You might compare the current props to the previous ones and decide
whether you need to fetch new data or focus an input, for example.
Deprecated Lifecycle Methods

React has deprecated a few lifecycle methods to promote safer coding


practices, and you should avoid using them in new code:

- `componentWillUpdate(nextProps, nextState)`
- `componentWillReceiveProps(nextProps)`
- `UNSAFE_componentWillUpdate(nextProps, nextState)`
- `UNSAFE_componentWillReceiveProps(nextProps)`

Instead of these, you should use the newer lifecycle methods mentioned above
and employ techniques such as the use of the `getDerivedStateFromProps`
method or the Hooks API for function components.

1. Pure Components

In React, a PureComponent is a type of component that implements


`shouldComponentUpdate` with a shallow prop and state comparison. It helps
optimize performance by reducing unnecessary renders.

Advantages:
- Helps in avoiding unnecessary re-renders.
- Can improve performance in many scenarios.

Example:

import React, { PureComponent } from 'react';


class MyPureComponent extends PureComponent {
render() {
return <div>{this.props.name}</div>;
}
}

2. React's DOM Updating

React employs a virtual DOM. When state or props change in a component:

1. A new virtual DOM tree is generated.


2. This new tree is compared to the previous one using a "diffing" algorithm.
3. The minimal number of changes to update the real DOM are calculated
based on this diff.
4. The real DOM is updated.

Advantages:
- Increases efficiency by only updating changed parts of the real DOM.
- Provides a way to optimize even further with lifecycle methods or hooks.

3. Fragments

Fragments let you return multiple child elements without adding extra nodes
to the DOM.

Advantages:
- No unnecessary wrapping divs.
- More semantic HTML output.
- Can be a performance boost.

Example:

import React, { Fragment } from 'react';

function Columns() {
return (
<Fragment>
<td>Hello</td>
<td>World</td>
</Fragment>
);
}

You can also use the short syntax: `<>` and `</>`

4. Higher Order Components (HOCs)

HOCs are functions that take a component and return a new component with
added props or altered behavior.

Advantages:
- Promotes code reusability.
- Can modify props or state before rendering.
- Provides a way to abstract and modularize component behaviors.

Example:

function withData(WrappedComponent, dataSource) {


return class extends React.Component {
constructor(props) {
super(props);
this.state = {
data: dataSource
};
}

render() {
return <WrappedComponent data={this.state.data} {...this.props} />;
}
};
}

class MyComponent extends React.Component {


render() {
return <div>{this.props.data}</div>;
}
}

const MyComponentWithData = withData(MyComponent, "Hello from HOC!");


In the above example, `withData` is a HOC that wraps `MyComponent` and
provides it with a `data` prop.

You might also like