Learn React Hooks
Hooks are a new addition in React 16.8. They allow us to use React features without writing a class based components. There are 3 Basic Hooks and other hooks are either variants of the basic ones , or only needed for specific edge cases.
In this article we cover almost all hooks.
- useState
- useEffect
- useContext
- useReducer
- useMemo, React.memo
- useCallback
- useRef, callbackRef, forwardRef
- useImperativeHandle
- useLayoutEffect
- useDebugValue
BASIC HOOKS
1. useState
Returns a stateful value, and a function to update it
const [state, setState] = useState(initialState);
The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.If your update function returns the exact same value as the current state, the subsequent re render will be skipped completely.The initialState
argument is the state used during the initial render. In subsequent renders, it is disregarded (fig 1.2).
2. useEffect
The function passed to useEffect
will run after the render is committed to the screen.useEffect Hook can express all combinations of these componentDidMount, componentDidUpdate, componentWillUnmount.
useEffect(didUpdate); useEffect(()=>{},[dependencies])
If we write the useEffect without square brackets then the function passed to useEffect will run on every render.
initial rendering happens before mounting. Rendering returns the elements which are supposed to be mounted in the DOM. Mounting a react component means the actual addition of the DOM elements created by the react component into the browser DOM for the first time.The main difference between mounting and rendering is that mounting happens once, but rendering can happen any number of times.
- Function Passed to useEffect will run on every re render if no dependency is passed (fig-2.1).
- componentDidMount and componentWillUnmount If dependency is an empty array then it will behave like componentDidMount and componentWillUnmount (fig- 2.2).
- if we only want to re render the component in change of any state or prop then pass the state or prop in dependency array (fig 2.3).
- componentDidUpdate sometimes we want the function to run only on update not on mount then we can write like fig 2.3. Here Did Update will only log when ‘click’ change its value. it will not print in its first render.
if we pass object , array and function in dependency then the function passed to useEffect will run on every render. Object reference will change on every re render.
3. useContext
Context provides a way to pass data through the component tree without having to pass props down manually at every level like user, theme, or preferred language.
const value = useContext(MyContext)
const ContextName = React.createCotext(initialvalue);
When the nearest <MyContext.Provider> above the component updates, this Hook will trigger a re render with the latest context value. Here theme object is passed as a context. we can access its value without manually passing the props at every level.
Other Hooks
4. useReducer
const [state, dispatch] = useReducer(reducer, initialArg, init);
(state, action) => newState
Why useReducer, If useState can also update the State
when there is complex state logic that involves multiple sub-values or when the next state depends on the previous one and also to optimise the performance that has deep updates because we can pass dispatch down instead of callbacks. Dispatch reference will not create on every re render but callback reference will create in each re render.
- Use useState whenever you manage a JS primitive
- Use useReducer whenever you manage an object or array
sometimes we want to manage the state at top-level but want to trigger state changes somewhere deep down in our component tree. It’s possible to pass both the updater function from useState or the dispatch function from useReducer as a props in component tree but using context may be a better alternative to avoid prop drilling (passing props through each component level). In that case, having one dispatch function with different action types and payloads may be a better option than using multiple updater functions from useState that must be passed down individually. The dispatch function can be passed down once with useContext Hook.
React.memo , useMemo and useCallback hooks are used for optimisation. Their motive is to prevent unnecessary renders.
React.memo similar to pureComponent in class components and used for a performance boost in some cases by memoizing the result. This means that React will skip re rendering the component, and reuse the last rendered result.
In fig 5.1 we update the value of count1 and component will re render but one thing you notice , <Count> does not use ‘click’ state but <Count> still re render because React Says that if parent re render then its child also re render until we used any optimisation. In order to prevent the re rendering of <Count> we can use React.memo. It checks for props changes and will skip re rendering the component if props value are same. In this example <Count> will not re render if we use React.memo.
If we pass object, array or function as a prop then React.memo will not work because their new reference will create on each re render and React.memo uses reference equality to prevent unnecessary renders.
5. useCallback and useMemo
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
)
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
In fig 5.2 you can see that the main difference is , React.useMemo will call the Function and return its result while React.useCallback will return the function without calling it .
In fig 5.3 Function is passed as a prop in <Actions> and on changing the state of ‘check’ <Actions> will re render . In this case we can not use React.memo because new reference of function will generate on each re render. we want that the function reference will not create until some dependency will change.If function is pass in useCallback then the function reference will not generate. Function reference will only generate if any state or props passed in the dependency array will change.
useMemo returns memoized value.Imagine that you’ve got a function that synchronously calculates a value which is computationally expensive to calculate.With useMemo, we never have to calculate the same value twice .we can use same value again until dependencies array’s values will change. If our dependencies array is empty, there is no possibility of memoization and it will compute a new value on every render.
6. useRef
It can used as a way to access the DOM. If we pass ref object to React with <div ref={myRef} />.useRef can persist a value for a full lifetime of the component.
const refContainer = useRef(initialValue);
Here question is if createRef exist then why there is need for useRef.
createRef will return a new ref on every render.Every invocation of createRef will generate a new object. It is perfect for a class component’s constructor.while useRef will return the same ref each time.
In fig 6.2 on click we set the current property of ref and component will not re render that means useRef doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render.
We can use useCallbackRef , the callback ref will be invoked when a component mounts and be set to null when the component un mounts.
In fig 6.3 ‘ref set’ will log when <input> added to DOM and will log again when <input> tag unmount.
useImperativeHandle before this we need to know about useForwardRef.
can we pass ref as a prop?
No, ref is a reserved word like key. We can’t pass it like a prop. Ref forwarding is a technique for automatically passing a ref through a component to one of its children. In fig 7.1 we create a ref in <Hello> and pass it to <RefCom> using forwardRef.
7. useImperativeHandle
It should be used with forwardRef.Expose limited DOM methods (such as select, focus, click, etc.) to callers and provide normal methods to callers.
In fig 7.2 we can use extra function log() using useImperativeHandle i.e It customises the instance value that is exposed to parent components when using ref .use useImperativeHandle
to expose a handle with only the methods that you want the parent component to call. We should only use refs for imperative behaviors that you can’t express as props: for example, scrolling to a node, focusing a node, triggering an animation, selecting text, and so on.
8. useLayoutEffect
If you need to mutate the DOM and do need to perform measurements.Your code runs immediately after the DOM has been updated, but before the browser has had a chance to “paint” those changes.
Difference between useEffect and useLayoutEffect?
Only differs in when it is fired.The function passed to useEffect fires after layout and paint, during a deferred event.The function passed to useLayoutEffect fires before paint like componentDidMount.
9. useDebugValue
The main purpose of this hook, is to help with debugging.It works with React Developer Tools to show the value of the hook that is useful for us to understand the state of the Component that our hook is managing
useDebugValue(value, [optional formatting function]);
In fig 9.1 second is not correct way because formattedDate value will always calculate.useDebugValue function is only called if the Hooks are inspected. It receives the debug value as a parameter and should return a formatted display value.
Last words
Feel free to convert Class based component to React Hooks. Make your code more readable, optimised and short. Please let me know if something isn’t clear, and I’d be happy to chat about your concerns.
Thanks for Reading !!