Mastering how to use React refs with TypeScript

    Tuesday, July 23, 20249 min read517 views
    Mastering how to use React refs with TypeScript

    Table of Contents

    1. Introduction to Refs in React

    2. Basic Usage of Refs in React with TypeScript

    3. Typing Refs in TypeScript

    4. Best Practices for Using Refs in TypeScript

    5. Conclusion

    Introduction to Refs in React

    What are Refs?

    Refs (short for references) are a special feature in React that allows you to directly access and interact with DOM elements or React components. While React promotes a declarative approach to building user interfaces, there are situations where you need to imperatively interact with a DOM element or a component instance. Refs provide a way to do this.

    Use Cases for Refs in React

    Refs can be particularly useful in the following scenarios:

    1. Managing Focus: When you need to programmatically set the focus on an input field, such as when a form is submitted or a modal is opened.

    2. Reading Values: Accessing the current value of a DOM efficiently element, such as reading the value of an input field without using controlled components.

    3. Triggering Animations: When you need to trigger animations directly on a DOM element.

    4. Integrating with Third-Party Libraries: When you need to interact with third-party DOM libraries that are not built with React.

    5. Handling Media: Controlling media elements like playing or pausing a video or audio element.

    Basic Usage of Refs in React with TypeScript

    Using refs in React with TypeScript involves creating and managing references with proper type annotations. This ensures type safety and helps catch errors during development. Here’s a step-by-step guide on how to use refs in both class and functional components with TypeScript and avoid typescript error.

    • Creating Refs in Functional Components

    In functional components integrating react, refs are typically created using the react's `useRef` hook. The `useRef` hook returns a mutable ref object whose `.current` property is initialized to the passed argument (or `null` if no argument is provided).

    Here’s how to create and use refs in a functional component:

    import React, { useRef, useEffect } from 'react';
    const App: React.FC = () => {
      const inputRef = useRef<HTMLInputElement>(null);
      const ref;
      useEffect(() => {
        if (inputRef.current) {
          inputRef.current.focus(); // Accessing DOM elements and setting focus
        }
      }, []);
      return <input type="text" ref={inputRef} />;
    };
    export default App;

    In this example:

    - `useRef<HTMLInputElement>(null)` creates a ref that will eventually hold a reference to an HTML input element.

    - The `useEffect` hook is used to focus the input element when the component mounts.

    • Creating Refs in Class Components

    In class components, refs are created using the `React.createRef` method. This method returns a ref object which can be assigned to an instance variable.

    Here’s how to create and use refs in a class component:

    import React, { Component } from 'react';
    class MyComponent extends Component {
      private inputRef: React.RefObject<HTMLInputElement>;
      constructor(props: {}) {
        super(props);
        this.inputRef = React.createRef();
      }
      componentDidMount() {
        if (this.inputRef.current) {
          this.inputRef.current.focus(); // Accessing the DOM element and setting focus
        }
      }
      render() {
        return <input type="text" ref={this.inputRef} />;
      }
    }
    export default App;

    In this example:

    - `React.createRef<HTMLInputElement>()` creates a ref that will eventually hold a reference to an HTML input element.

    - The `componentDidMount` lifecycle method is used to focus the input element when the component mounts.

    • Using Refs with Custom Components

    You can also use refs to access custom React components. This can be useful when you need to call methods or access properties on child components.

    Here’s an example of how to do this:

    import React, { forwardRef, useRef, useImperativeHandle } from 'react';
    // Define the child component
    const ref;
    const ChildComponent = forwardRef((props, ref) => {
      const localRef = useRef<HTMLDivElement>(null);
      useImperativeHandle(ref, () => ({
        focus: () => {
          if (localRef.current) {
            localRef.current.focus();
          }
        }
      }));
      return <div tabIndex={-1} ref={localRef}>Focusable Div</div>;
    });
    const ParentComponent: React.FC = () => {
      const childRef = useRef<{ focus: () => void }>(null);
      const handleFocusClick = () => {
        if (childRef.current) {
          childRef.current.focus(); // Call the focus method on the child component
        }
      };
      return (
        <div>
          <ChildComponent ref={childRef} />
          <button onClick={handleFocusClick}>Focus the Child Component</button>
        </div>
      );
    };
    export default ParentComponent;

    In this above example:

    - `ChildComponent` is a custom component that forwards its ref using `forwardRef` and exposes a `focus` method using `useImperativeHandle`.

    - `ParentComponent` creates a react's ref to `ChildComponent` and calls the `focus` method when a button is clicked.

    Typing Refs in TypeScript Using `React.RefObject` &`React.MutableRefObject`

    In TypeScript, it’s important to type your refs correctly to ensure type safety and avoid typescript error. React provides two main types for refs: `React.RefObject` and `React.MutableRefObject`. Understanding the differences between these and knowing when to use each one is crucial.

    `React.RefObject`

    `React.RefObject` is used for immutable refs created using `React.createRef` or `useRef` in functional components where the initial value is `null`. This type is read-only and should be used when you don't need to reassign the ref object itself after initialization.

    Example in Class Components:

    import React, { Component } from 'react';
    class MyComponent extends Component {
      private inputRef: React.RefObject<HTMLInputElement>;
      constructor(props: {}) {
        super(props);
        this.inputRef = React.createRef();
      }
      componentDidMount() {
        if (this.inputRef.current) {
          this.inputRef.current.focus(); // Accessing the DOM element and setting focus
        }
      }
      render() {
        return <input type="text" ref={this.inputRef} />;
      }
    }
    export default MyComponent;

    In this example:

    - `inputRef` is typed as `React.RefObject<HTMLInputElement>`.

    - This type is used because `React.createRef` is used to create complex object from the ref, and its initial value is `null`.

    Example in Functional Components

    import React, { useRef, useEffect } from 'react';
    const MyComponent: React.FC = () => {
      const inputRef = useRef<HTMLInputElement>(null);
      useEffect(() => {
        if (inputRef.current) {
          inputRef.current.focus(); // Accessing the DOM element and setting focus
        }
      }, []);
      return <input type="text" ref={inputRef} />;
    };
    export default MyComponent;

    In this example:

    - `inputRef` is typed as `React.RefObject<HTMLInputElement>`.

    - `useRef<HTMLInputElement>(null)` creates a ref with an instance variable of `null`.

    React.MutableRefObject`

    `React.MutableRefObject` is used for refs created using react's `useRef` hook in functional components where the initial value is not `null`. This type is a mutable object, meaning the ref object’s `.current` property can be reassigned after initialization.

    Example with Mutable Initial Value:

    import React, { useRef, useEffect } from 'react';
    const CounterComponent: React.FC = () => {
      const countRef = useRef<number>(0); // Mutable ref with an initial value of 0
      useEffect(() => {
        const timer = setInterval(() => {
          countRef.current += 1;
          console.log('Count:', countRef.current);
        }, 1000);
        return () => clearInterval(timer);
      }, []);
      return <div>Open the console to see the count</div>;
    };
    export default CounterComponent;

    In this example:

    - `countRef` is typed as `React.MutableRefObject<number>`.

    - The ref is used to to store values as a mutable value that is updated inside a timer.

    Summary of Differences

    - `React.RefObject<T>`: Read-only ref, usually used with `React.createRef` or `useRef(null)`. The initial value of ref attribute is `null`, and the ref object should not be reassigned.

    - `React.MutableRefObject<T>`: Mutable ref, used with `useRef` when the initial value is not `null`. The `.current` property can be reassigned.

    Secure User Access and Data With React
    Angular Minds a
    React Development Company is proficient in safeguarding your React application and user information with authentication and authorization.

    Best Practices for Using Refs in TypeScript

    Using refs in React with TypeScript can greatly enhance your application's functionality and reliability. However, to ensure your code remains maintainable and robust, it's important to follow some best practices.

    1. Use Refs Sparingly

    Refs should be used only when necessary. Rely on the declarative approach of React as much as possible. Refs are typically used in scenarios where you need to:

    - Access a DOM element directly (e.g., for focusing an input).

    - Integrate with third-party libraries.

    - Trigger animations.

    - Manage imperative actions.

    2. Properly Type Your Refs

    Always provide appropriate types for your refs to ensure type safety. This helps catch errors during compile time and improves code readability.

    const inputRef = useRef<HTMLInputElement>(null); // Correctly typed ref

    3. Initialize Refs Correctly

    When using `useRef` in functional components, ensure you initialize it with `null` if it will initially be empty. This makes it clear that the ref might not have a value right away.

    const inputRef = useRef<HTMLInputElement>(null); // Initialize with null

    4. Check for Ref Nullability

    Always check if the ref's current value is not `null` before you gain direct access to its properties or methods. This avoids runtime errors when the ref is not yet assigned.

    useEffect(() => {
        if (inputRef.current) {
          inputRef.current.focus(); // Safely access the ref's current value
        }
      }, []);

    5. Avoid Using Refs for State Management

    Do not use refs as a substitute for state. Refs should not be used to trigger re-renders or store state that affect rendering. Use state variables for such purposes.

    const [count, setCount] = useState(0); // Use state for values that affect rendering

    Conclusion

    Using refs in React with TypeScript enhances your ability to interact directly with DOM elements and component instances in a type-safe manner. Refs provide a way to access and manipulate DOM elements or React component instances directly, which is useful for managing focus, reading values, triggering animations, and integrating with third-party libraries.

    Following best practices is essential when working with refs. Use refs sparingly and only when necessary, relying on React's declarative approach for most tasks. Always check for nullability before accessing ref properties or methods to avoid common runtime errors here.

    Refs should not be used for state management; state variables are more appropriate for values that affect rendering. When exposing custom component APIs, use `useImperativeHandle` to control what gets exposed, keeping internal details encapsulated.

    24

    Related articles

    This website uses cookies to analyze website traffic and optimize your website experience. By continuing, you agree to our use of cookies as described in our Privacy Policy.