Forwarding Refs - anastasiamexa/react-complete-guide-course-resources GitHub Wiki

In React, forwarding a ref refers to a technique where a child component allows its parent or ancestor component to access and interact with the child's DOM element or React component. This is often useful in cases where you have a composite component (composed of multiple sub-components) and the parent component needs to manage or interact with the child's internal details.

Here's a step-by-step explanation of how forwarding a ref works:

1. Create a Ref in the Parent Component:
In the parent component, you create a ref using the useRef hook or React.createRef().

import React, { useRef } from 'react';

function ParentComponent() {
  const childRef = useRef();
  // ...
}

2. Pass the Ref to the Child Component:
You pass the ref to the child component as a prop.

import React, { useRef } from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
  const childRef = useRef();

  return <ChildComponent forwardedRef={childRef} />;
}

3. Access the Ref in the Child Component:
In the child component, you use the forwardedRef prop and the React.forwardRef function to forward the ref to a specific DOM element or another child component.

import React, { forwardRef } from 'react';

const ChildComponent = forwardRef((props, ref) => {
  // Use the forwarded ref to attach it to a DOM element or another component
  return <div ref={ref}>Child Component</div>;
});

export default ChildComponent;

The forwardRef function takes a render function as its argument, and this function receives the ref as its second argument. You use this ref to attach it to the desired element or component.

4. Access the Ref in the Parent Component:
Now, in the parent component, you can access and interact with the child's DOM element or component using the ref.

import React, { useRef, useEffect } from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
  const childRef = useRef();

  useEffect(() => {
    // Access and interact with the child's DOM element or component
    console.log(childRef.current);
  }, [childRef]);

  return <ChildComponent forwardedRef={childRef} />;
}

By forwarding the ref from the parent to the child and then from the child to the specific DOM element or component, you allow the parent component to manage or interact with the internals of the child component.

This pattern is especially useful when creating reusable components or when you need to coordinate actions between parent and child components.

Example

// Input.js
import { forwardRef } from 'react';

const Input = forwardRef(function Input({ type, label }, ref) {
  return (
    <p className="control">
      <label>{label}</label>
      <input type={type} ref={ref} />
    </p>
  );
});

export default Input;

Explanation:

  • The Input component uses forwardRef to forward the ref to the input element inside it.
  • The ref is passed as a second parameter to the functional component.
  • The input element uses this forwarded ref so that the parent component can access the underlying DOM element.
// App.js
import { useRef } from 'react';
import Input from './Input';

export const userData = {
  name: '',
  email: '',
};

export function App() {
  const nameInput = useRef();
  const emailInput = useRef();

  function handleSaveData() {
    // Access the values of the input elements using the refs
    userData.name = nameInput.current.value;
    userData.email = emailInput.current.value;

    console.log(userData);
  }

  return (
    <div id="app">
      {/* Forwarding the refs to the Input components */}
      <Input ref={nameInput} type="text" label="Your Name" />
      <Input ref={emailInput} type="email" label="Your E-Mail" />
      <p id="actions">
        <button onClick={handleSaveData}>Save Data</button>
      </p>
    </div>
  );
}

Explanation:

  • In the App component, two useRef hooks (nameInput and emailInput) are created.
  • These refs are then passed to the respective Input components as the ref prop.
  • When the "Save Data" button is clicked, the handleSaveData function is called.
  • Inside this function, the values of the input elements are accessed using the refs (nameInput.current.value and emailInput.current.value).
  • The values are then stored in the userData object and logged to the console.

This example illustrates how forwarding refs allows the parent component (App) to interact with the internal elements of the child components (Input) without exposing the details of the child components' implementation.

useImperativeHandle

The useImperativeHandle is a React Hook that allows you to customize the instance value that is exposed when using React.forwardRef. It is often used in conjunction with forwardRef to provide a more controlled and specific API to parent components when interacting with child components.

The primary use case for useImperativeHandle is to expose specific methods or values from a child component's instance to its parent, allowing the parent to interact with the child in a controlled manner.

import { forwardRef, useImperativeHandle, useRef } from 'react';

const Form = forwardRef(function Form({}, ref) {
  const formRef = useRef();

  useImperativeHandle(ref, () => {
    return {
      clear() {
        formRef.current.reset();
      },
    };
  });

  return (
    <form ref={formRef}>
      {/* ... input fields and other form elements */}
    </form>
  );
});

export default Form;
  • The Form component uses forwardRef to allow the parent component to access its internal formRef.
  • Inside useImperativeHandle, it exposes a clear method through the forwarded ref. This method calls reset on the form element, effectively clearing the form inputs.
import { useRef } from 'react';
import Form from './Form';

export function App() {
  const form = useRef();

  function handleRestart() {
    form.current.clear();
  }

  return (
    <div id="app">
      <button onClick={handleRestart}>Restart</button>
      <Form ref={form} />
    </div>
  );
}
  • The App component creates a ref (form) using useRef.
  • When the "Restart" button is clicked, the handleRestart function is called, which then invokes the clear method exposed by the Form component through the forwarded ref.

This pattern allows the parent component to have controlled access to specific functionality within the child component. In this case, the parent can trigger a form reset without having to directly manipulate the DOM or manage the internal state of the Form component. The use of forwardRef and useImperativeHandle provides a clean and explicit way to expose functionality from child to parent while maintaining encapsulation.

⚠️ **GitHub.com Fallback** ⚠️