In this blog we are going to talk about React hooks that are not used commonly.
1. useMemo Hook :
The useMemo is a hook used in the functional component of react that returns a memoized value.In react also, we use this concept, whenever in the React component, the state and props do not change the component and the component does not re-render, it shows the same output.
Syntax :
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useMemo takes in a function and an array of dependencies.
Usage of useMemo :
const memoizedList = useMemo(() => {
return userList.map(user => {
return {
...user,
name: someExpensiveOperation(user.name)
}
})
}, [userList])
2. useCallback Hook :
The useCallback hook is used when we have a component in which the child is rerendering again and again without need.
Syntax :
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
Pass an inline callback and an array of dependencies. useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed.
Purpose of useCallback
function MyComponent() {
// handleClick is re-created on each render
const handleClick = () => {
console.log('Clicked!');
};
// ...
}
handleClick is a different function object on every rendering of MyComponent.
But in some cases you need to maintain a single function instance between renderings:
- A functional component wrapped inside React.memo() accepts a function object prop
- When the function object is a dependency to other hooks, e.g. useEffect(..., [callback])
- When the function has some internal state, e.g. when the function is debounced or throttled.
That’s when useCallback(callbackFun, deps) is helpful: given the same dependency values deps, the hook returns (aka memoizes) the function instance between renderings:
import { useCallback } from 'react';
function MyComponent() {
// handleClick is the same function object
const handleClick = useCallback(() => {
console.log('Clicked!');
}, []);
// ...
}
3.useReducer Hook :
useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one.
Syntax
const [state, dispatch] = useReducer(reducer, initialArg, init);
It accepts a reducer of type (state, action) => newState, and returns the current state paired with a dispatch method. (If you’re familiar with Redux, you already know how this works.
Here is the countReducer example;
const initialState = { count: 0 }
const counterReducer = (state, action) => {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
Specifying the initial State
Two ways to initialized the useReducer state;
1. Basic :
We can just give it as a second argument to useReducer call;
const [state, dispatch] = useReducer(
countReducer,
{ count: 0 } // second argument
);
2. Lazy Initialization :
const initState = (defaultCount) => ({ count: defaultCount })
const Counter = ({ counter }) => {
const [state, dispatch] = useReducer(
countReducer,
counter, // second argument
initState // third argument
);
// Rest of the component...
}
Usage
After we initialize it we just need to call dispatch functions that we are getting from useReducer hook and use it as a handler inside our elements.
React guarantees that dispatch function identity is stable and won’t change on re-renders.
const Counter = ({ counter }) => {
const [state, dispatch] = useReducer(countReducer, 0);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
Top comments (0)