Real Life Example - UseImperativeHandle
Tags: react, javascript, hooks, webdev
Published: 2022-03-19 14:20:00

## 1. Wait wait...what is it?

`useImperativeHandle` allows us to <u>pass values and functions</u> from a **Child** component to a **Parent** using a `ref`. 
From there, the Parent can either use it itself or pass it to another Child.

> Note that you can only pass a ref as a prop to a child that wraps its component in `forwardRef`.

---

Code examples are much better than words when it comes to understanding so here is one:

```react
// Parent Component
const App = () => {
  const ref = useRef();

  return (
    <div>
      <ComponentWithButton ref={ref} />
      <button onClick={() => ref.current.increment()}>another button</button>
    </div>
  );
};

// Child Component
const ComponentWithButton = forwardRef((props, ref) => {
  useImperativeHandle(ref, () => ({increment}))

  const [count, setCount] = useState(0);
  const increment = () => setCount(count + 1);
  return (
    <div>
      <button onClick={increment}>click</button>
      <h2>Count: {count}</h2>
    </div>
  )
})

```


In the example above, we are changing the count variable in the parent component with the help of `useImperativeHandle` and `forwardRef`.


## 2. Why?

The general pattern in React is to have a **unidirectional** flow of data.
In cases where **bidirectional** dataflow is needed, we can use libraries such as `Redux` or `React context`. 

However, in some cases, using those is simply just overkill.
This is where `useImperativeHandle` comes in. 

---

**Now that we have some understanding of the hook and when we want to use it let's move to the Real Life Example...**

We have a `Settings` page that allows the user to update and edit his information and notification preferences.

The component has `sections` and every section is a form that is responsible for changing data related to the user (A section for his profile info, his privacy settings, and his notifications settings).

```react
const Section = ({ name, text, fields, schema }) => {
  const { control, handleSubmit, reset, formState } = useForm({
    mode: 'onChange',
    defaultValues: fields.reduce((acc, field) => ({ ...acc, [field.name]: field.defaultValue }), {})
  });

  return (
    <section className={styles.section}>
      <Title text={text} />
      <form onSubmit={handleSubmit(onSubmit)}>
        {fields.map(field => (
          <Field key={field.name} {...field} control={control} />
        ))}
      </form>
    </section>
  );
};
```
Every `section` is rendered in the `Settings` component - The Parent Component:

```react
const Settings = () => (
   <main className={styles.main}>
     {SECTIONS.map(section => (
        <Section key={section.name} {...section}  />
      ))}
   </main>
);
```

Supposedly, everything is fine a Parent component that renders children...but what happens when we want to trigger the submit function of every section by clicking a global button? 
We will need some way to allow the parent to control, that's where `useImperativeHandle` comes in.

We will add the hook in the `Section` component and wrap it with the forward ref so that we can pass a ref from `Settings`:

```react
const Section = React.forwardRef(({ name, text, fields, schema },ref) => {
  const { control, handleSubmit, reset, formState } = useForm({
    mode: 'onChange',
    defaultValues: fields.reduce((acc, field) => ({ ...acc, [field.name]: field.defaultValue }), {})
  });


  useImperativeHandle(ref, () => ({
    submit() {
     handleSubmit(onSubmit)();
    }
  }));


  return (
    <section className={styles.section}>
      <Title text={text} />
      <form onSubmit={handleSubmit(onSubmit)}>
        {fields.map(field => (
          <Field key={field.name} {...field} control={control} />
        ))}
      </form>
    </section>
  );
});
```

With the help of the hook we are able to create some sort of an API for the parent to use, in this example we are exposing the `submit()` function that we we'll be able to call.

Now our `Settings` component will look like so:

```react
const Settings = () => {
 const refProfile = useRef();
 const refNotifications = useRef();
 const refPrivacy = useRef();

// The SECTIONS object is a configuration object that will
// hold the refs among the rest of the data

 const onSubmitAll = () => {
    SECTIONS.forEach(({ ref }) => {
      ref.current.submit();
    });
  };

  return (
     <main className={styles.main}>
       {SECTIONS.map(section => (
       // The ref of each section i passed here in the spread 
       // operation.
          <Section key={section.name} {...section}  />        
        ))}
     </main>
  );
}
```

That's it! We did it!
We Passed the control back to the parent without importing or using a more complex library.

![We Did It](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zymqlbrb3q6smtu86c0.png) 


---

## 3. Conclusion

I don't mean to disappoint but React doesn’t recommend using this hook. (there will most likely be another way in which you can do this without using the hook.)


Full disclosure, I ended up changing the component structure
But! nonetheless, it was super fun learning about this mysterious hook that is rarely used.

**I hope you had fun too 🙏🏼 Thank you for reading!!**

![Well that was fun](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/43xuut5srkphggivkymn.png)