victor chisom
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 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.

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully