# Understanding Forward Ref in React ## Introduction We'll talk about `forwardRef` in this article as another Refs notion. However, before understanding `forwardRefs` we have to first grasp what ref is, why we have to use it, and how to build it. When creating a React app, there are various circumstances where we must send a ref from the parent component to its child component to access the child component's DOM element. We are aware that React uses `Props` to aid data flow from top to bottom. So, we can send `Props` from the parent to the child component if we need to change the behavior of the latter. The React documentation states: > A ref can be automatically passed via a component to one of its children using the ref forwarding approach. For the majority of the application's components, this is often not required. Yet, it can be helpful for specific types of components, particularly in libraries of reusable components. ## What is Ref? In React, a ref is a special attribute provided by the React library that allows us to gain direct access to a component instance or DOM element. It provides a convenient way to reference and manipulate the underlying elements or values of a component without relying solely on props. Ref is particularly useful in scenarios where we need to update the value or trigger specific actions on a child component directly, without involving props or triggering a re-render of the entire component hierarchy. One advantage of using refs is the ability to use callbacks with them. By utilizing callback functions, we can perform various actions such as updating state, accessing properties or methods, or triggering specific behaviors on the referenced component or element. Example: ```javascript // without refs import React, { useState } from "react"; const App = () => { const [sayings, setSayings] = useState(""); const update = (e) => { setSayings(e.target.value); }; return ( <div> Mukul Says <input type="text" onChange={update} /> <br /> <em>{sayings}</em> </div> ); }; export default App; ``` In the example above, the target value of event `e` is used to determine the significance of what Mukul is saying. The refs can also be used to get the results mentioned above. ```javascript import { useState, useRef } from "react"; function App() { const [sayings, setSayings] = useState(""); const anythingRef = useRef(null); const update = () => { setSayings(anythingRef.current.value); }; return ( <div> Mukul Says <input type="text" ref={anythingRef} onChange={update} /> <br /> <em>{sayings}</em> </div> ); } export default App; ``` React's refs are utilized in the examples above; they may also be used to embed `callback` functions, which is useful in many situations. ```javascript import { useState, useRef } from "react"; function App() { const [sayings, setSayings] = useState(""); const inputRef = useRef(null); const update = () => { setSayings(inputRef.current.value); }; return ( <div> Mukul Says{" "} <input type="text" ref={(call_back) => { inputRef.current = call_back; }} onChange={update} /> <br /> <em>{sayings}</em> </div> ); } ReactDOM.render(<App />, document.getElementById("root")); ``` ## How to create Ref in React Although we generally adhere to the component-based architecture when creating React apps, there may be times when you need to manipulate or urgently change a DOM element. The following are ideal use cases for using refs, according to the React documentation: * controlling media playback, text selection, or focus. * imperative animations being triggered. * including external DOM libraries. > NOTE: Refs should not be used throughout the app. The use of references is not necessary if the tasks can be completed declaratively. ### Using Callback Ref Callback Refs in React are a way to access DOM elements in functional components. By giving a callback function to the `ref` prop, the function accepts input in the form of DOM elements, which we may store in variables and use later in the application. Let's consider an example where we have an input element that should receive focus when a user clicks a button. We can create a component with an input and a button, and utilize the `useRef` hook to create a ref to the `input` element. ```jsx import React, { useState, useRef } from "react"; import "./App.css"; function App() { const [inputValue, setInputValue] = useState(""); const inputRef = useRef(null); const handleButtonClick = () => { console.log("Callback Ref:", inputRef.current.value); inputRef.current.focus(); inputRef.current.disabled = true; inputRef.current.style.backgroundColor = "rgba(255, 0, 0, 0.3)"; }; const setInputRef = (inputElement) => { inputRef.current = inputElement; }; return ( <div className="container"> <h1 className="title">Refs in React</h1> <h3 className="subtitle">Using Callback Ref:</h3> <div className="input-container"> <input type="text" className="input" onChange={(e) => setInputValue(e.target.value)} ref={setInputRef} /> <button className="button" onClick={handleButtonClick}> Click </button> </div> </div> ); } export default App; ``` In this above snippet, we have a functional component called `App` which uses the `useState` and `useRef` hooks from React. The `handleButtonClick` function is modified to log the value of the input field using `inputRef.current.value`, and then sets focus on the input element. Additionally, the input is disabled and styled with a slightly transparent red background. The `setInputRef` function is defined to take an input element as an argument and sets the current property of the `inputRef` object to the input element reference. The JSX code incorporates the `classNames` for styling purposes and renders the input element, button, and related elements with appropriate CSS classes. So the final output looks like this: ![](https://hackmd.io/_uploads/rkC9GzqU2.gif) ### Using React.createRef() API React's `createRef()` API, introduced in version 16.3, simplifies ref creation by eliminating the need for callback functions. By using this API, you can effortlessly create a ref, store it, and then associate it with a DOM element's ref prop. Imagine you're building a feature where users can toggle the visibility of an image with a button click. Here's how you can implement this using the `createRef()` API: ```jsx import React, { useRef } from "react"; import "./styles.css" export default function App() { const imageRef = useRef(null); const handleToggleVisibility = () => { const currentDisplay = imageRef.current.style.display; imageRef.current.style.display = currentDisplay === "none" ? "block" : "none"; }; return ( <div> <h3>Toggle Image Visibility using React.createRef() and useRef:</h3> <img src="https://i.imgur.com/7nKHYrv.jpg" alt="Sample" ref={imageRef} style={{ display: "block" }} /> <button style={{ margin: "8px" }} onClick={handleToggleVisibility}> Toggle Image Visibility </button> </div> ); } ``` In this example, we've initialized a ref using `createRef()` and associated it with an image element. The `handleToggleVisibility` function toggles the image's visibility by adjusting its `display` style property. With a simple button click, users can now show or hide the image, enhancing interactivity. The same output result as before: ![](https://hackmd.io/_uploads/HyEzFTcan.gif) ### Using useRef() Hook The `useRef()` hook in React provides an elegant way to access and interact with DOM elements directly. It returns a mutable ref object, which can be associated with React elements during rendering. Let's delve into a practical example where we use the `useRef()` hook to control the playback of a video: ```jsx import React, { useRef } from "react"; import "./styles.css"; export default function VideoController() { const videoRef = useRef(null); const handleTogglePlayPause = () => { if (videoRef.current.paused) { videoRef.current.play(); } else { videoRef.current.pause(); } }; return ( <div className="video-container"> <h1>Interacting with Video using useRef()</h1> <h3>Play or Pause the Video:</h3> <video width="320" height="240" ref={videoRef}> <source src="https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4" type="video/mp4" /> Your browser does not support the video tag. </video> <button className="toggle-button" onClick={handleTogglePlayPause}> Toggle Play/Pause </button> </div> ); } ``` In the `VideoToggleExample` component, the `useRef` hook establishes a reference to a video element. The `handleTogglePlayPause` function checks the play state of the video and toggles between play and pause accordingly. The `videoRef` object, created using the `useRef` hook, is initialized to null. The video element in the JSX is then associated with this ref, ensuring that `videoRef.current` always points to the video DOM element. Output: ![](https://hackmd.io/_uploads/Hyxy2a9p2.gif) ## Advanced Ref Forwarding with React.forwardRef() In React, the `React.forwardRef()` API provides a powerful way to pass a ref from a parent component to a child component. This is particularly useful when you need to manipulate a child component's DOM element directly from the parent component. Let's explore this concept with a more advanced example: a parent component that controls the playback of an embedded video in a child component. ### Parent Component: VideoController Here's the code for the parent component, which we'll call `VideoController`. ```jsx import React, { useRef } from "react"; import VideoPlayer from "./VideoPlayer"; export default function VideoController() { const videoRef = useRef(null); const handlePlayPause = () => { videoRef.current.togglePlayPause(); }; return ( <div className="video-controller"> <h1>Video Controller</h1> <VideoPlayer ref={videoRef} /> <button className="control-button" onClick={handlePlayPause}> Play/Pause </button> </div> ); } ``` In the `VideoController` component, we create a ref using `useRef()` and pass it to the `VideoPlayer` child component. This ref will allow the parent component to directly control the video playback in the child component. ### Child Component: VideoPlayer Now let's look at the child component, `VideoPlayer`. ```jsx import React, { forwardRef, useImperativeHandle } from "react"; const VideoPlayer = forwardRef((props, ref) => { useImperativeHandle(ref, () => ({ togglePlayPause() { const video = document.getElementById("videoElement"); if (video.paused) { video.play(); } else { video.pause(); } }, })); return ( <div className="video-player"> <video id="videoElement" width="320" height="240"> <source src="https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4" type="video/mp4" /> </video> </div> ); }); export default VideoPlayer; ``` The `VideoPlayer` component uses `React.forwardRef()` to receive the ref from the parent. We also use `useImperativeHandle` to expose a method (`togglePlayPause`) that the parent can call. This method allows the parent component to toggle the play and pause state of the video. ![](https://hackmd.io/_uploads/H1ri4Oyyp.gif) By setting up the ref in this manner, the parent component can directly control the video playback in the child component, showcasing the power and flexibility of `React.forwardRef()`. ## Ways to avoid React Component Re-rendering There are two key steps that we need to consider while discussing React performance: - Initial render: This happens when a component is first displayed on the screen. - Re-render: This refers to any subsequent render of a component that is already on the screen. React re-rendering happens when the app needs to update with fresh data, which can result from user interactions, asynchronous data arriving, or subscription mechanisms. Non-interactive apps won't re-render as they don't have any asynchronous data changes to worry about. Despite significant development, developers still struggle with eliminating unnecessary re-rendering in React components. To address this issue, there are multiple methods available. In this article, we will discuss five ways to prevent React components from re-rendering unnecessarily. ### Memoization — using the `useMemo()` and `UseCallback() hooks` Memoization is a technique to reduce the number of re-renderings of React components by caching and delivering the same result when the inputs are the same without performing any calculations. There are two hooks provided by React to implement memoization: `useMemo()` and `useCallback()`. The `useMemo()` hook caches the computed result and returns it each time unless the inputs are updated. For example, if we have a function that multiplies two numbers, we can use `useMemo()` to store the result and avoid re-rendering the component each time the function is called with the same inputs: ```jsx const cachedValue = useMemo(() => multiply(x, y), [x, y]) ``` On the other hand, the `useCallback()` hook memoizes the callback function instead of caching the outcome. For instance, if we have a clickable item list in a component, we can use `useCallback()` to memorize the `onClick` callback and prevent the component from re-rendering each time the user clicks the same item: ```jsx import { useCallback } from "react"; export default function MyParent({ item }) { const onClick = useCallback( (event) => { console.log("Clicked Item : ", event.currentTarget); }, [item] ); return <List item={item} onClick={onClick} />; } ``` ### API call optimization with React Query In React apps, the `useEffect()` Hook is frequently used for asynchronous data fetching tasks. On the other hand, `useEffect()` runs and loads data on each render, frequently loading the same data. The React Query library can be used as a workaround to cache the response data. React Query will retrieve the data from the cache before continuing with the request when we make an API connection. If no fresh data is available, it will stop the component from re-rendering after retrieving the data from the server. ```javascript import React from "react"; import { useQuery } from "react-query"; import axios from "axios"; async function fetchArticles() { const { data } = await axios.get(URL); return data; } export default function Articles() { const { data, error, isError, isLoading } = useQuery( "articles", fetchArticles ); if (isLoading) { return <div>Loading...</div>; } if (isError) { return <div>Error! {error.message}</div>; } return <div>...</div>; } ``` ### Creating memoized selectors with Reselect Reselect is a third-party library that helps reduce unnecessary re-renders by creating memoized selectors. It's often used with Redux and provides useful functionality. Selectors that are memoized using Reselect can compute derived data and won't recompute unless their inputs change. They can be used as inputs for further selectors. The `createSelector` API from Reselect can generate memoized selector functions. Here's an example to help understand how it works: ```jsx import { useSelector } from "react-redux"; import { createSelector } from "reselect"; function MyComponent() { const value1 = useSelector((state) => state.values.value1); const value2 = useSelector((state) => state.values.value2); const selectedValue = useSelector( createSelector( [value1, value2], (v1, v2) => v1 + v2 ) ); return <div>{selectedValue}</div>; } ``` In this example, `createSelector` takes two selectors, `value1` and `value2`, and a function that combines them to produce `selectedValue`. The `useSelector` hook then returns the memoized version of `selectedValue`, which won't be recomputed unless `value1` or `value2` changes. ### Replace `useState()` with `useRef()` React applications frequently utilize the `React.useState()` API to re-render the components when the state changes. There are situations, though, where it's necessary to monitor state changes without redrawing the components. Instead of forcing component re-renderings, we can track state changes by using the `React.useRef()` API. ```javascript import React, { useRef, useState } from "react"; function App() { const [toggle, setToggle] = useState(false); const counter = useRef(0); console.log(counter.current++); return <button onClick={() => setToggle((toggle) => !toggle)}>Click</button>; } ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById("mydiv") ); ``` The toggle in the previous example causes the component to be rendered once every time the value is changed. Yet, because the `counter` is a changeable ref, its value is persistent. There will only be one render because we are using `useRef()`. `UseState()`, on the other hand, results in two renderings for each toggle. It's helpful to have this render `counter`. You could turn this into a unique hook that you could use repeatedly across projects with a straightforward `npm I @bit/your-username/use-render count command?` With an open-source toolchain like [Bit](https://bit.cloud/), you could accomplish that. ### Using React Fragments If you have experience using React, you are aware that each component must be wrapped in a single parent element. Even though it has nothing to do with re-rendering, did you realize that it has an impact on the total component rendering time? Use React Fragments to wrap the components as a workaround to lessen the burden on the DOM, which will speed up rendering and use less memory. ```javascript import React from 'react'; const App = () => { return ( <> <p>Hello</p> <p>World</p> </> ); }; export default App; ``` The majority of these solutions emphasize caching, and you can build them using either the built-in React Hooks or third-party frameworks. Also, by minimizing the memory overhead and preventing pointless re-rendering, these techniques will enhance the performance of your application. ## Conclusion Dealing with React's references can be complex because the `ref` prop behaves differently than other `props`, but as we figure out how to use `forwardRef`, it gets much simpler. The use of React Ref hook is a fantastic tool for directly manipulating the DOM and persisting data between renders without requiring a rerender. It should only be applied sparingly when React doesn't offer a superior substitute. I hoped that this tutorial could address all of your concerns regarding `ref` in React.