0

I am not able to find a use Case for useImperativeHandle Hook. Trying to Google and understand I came across a code sandbox showing an example of why the useImperitaveHandle Hook would be used. Here is the link to the codesandbox

https://codesandbox.io/s/useimperativehandle-example-forked-illie?file=/src/App.js

I modified the code to get it working without the useImperitaveHandle in the codesandbox link below. Can someone explain why the hook would be used as I believe that code can be written without it to provide the exact same functionality.

https://codesandbox.io/s/useimperativehandle-example-forked-2cjdc?file=/src/App.js

dracarys
  • 1,071
  • 1
  • 15
  • 31
  • 1
    Could that be because of the typo? You inverted the i and a in useImperativeHandle. You can find an explanation there: https://en.reactjs.org/docs/hooks-reference.html#useimperativehandle and another SO question here: https://stackoverflow.com/questions/57005663/when-to-use-useimperativehandle-uselayouteffect-and-usedebugvalue – Stéphane Veyret Nov 07 '20 at 12:15
  • Can you check again, I couldnt find the typo. Also I read both the docs as well as that SO question. But neither was satisfactory. Can you explain with and example why useImperativeHandle would be needed in the codesandbox link – dracarys Nov 07 '20 at 12:56
  • You are right that it can often be avoided. The docs actually advise against using it (and ref forwarding in general) when it’s possible to achieve the same functionality by passing props. – Linda Paiste Nov 07 '20 at 12:57
  • @LindaPaiste I understand that but there has to be some use case where useImperativeHandle will be irreplaceable and needs to be used, otherwise what is the point of creating it in the first place. I was just trying to find an example of that – dracarys Nov 07 '20 at 12:59
  • 1
    Some UI component libraries use it on inputs, etc. I think mainly to leave open the possibility that you the user might want to pass a ref through to the underlying DOM element in order to do something custom that the package authors haven’t explicitly planned for. So they use useImperativeHandle to implement their package functionality with the ref, but ref forwarding allows you to do other things as well. – Linda Paiste Nov 07 '20 at 13:09
  • @LindaPaiste Ya that makes sense, thats what the documentation and the other SO question also said. I have a somewhat better understanding now. Thanks – dracarys Nov 07 '20 at 13:10
  • Some usages: [material-ui](https://github.com/mui-org/material-ui/search?q=useImperativeHandle&type=), [ant-design](https://github.com/ant-design/ant-design/search?q=useimperativehandle&type=), [react-spring](https://github.com/pmndrs/react-spring/blob/e666ac8fe53c68cc33ca3b0ab577169a5794f161/packages/parallax/src/index.tsx) – Linda Paiste Nov 07 '20 at 13:17
  • 1
    @LindaPaiste I found a use case with an example where useImperativeHandler cannot be replaced. I will answer my own question to help anyone else who might have a similar problem – dracarys Nov 07 '20 at 13:37

1 Answers1

0

I found an example where this would be used. According to my understanding it will be mainly needed if you need to write some custom functionality for a library and will need some of the library's in built features.

In the example I will provide, I will write a custom CellEditor for the library ag-grid(Table library) because I want to select the value of the cell in the table using Material UI's autocomplete. Below is the code

import React, { useState, forwardRef, useImperativeHandle } from "react";

import MuiTextField from "@material-ui/core/TextField";
import MuiAutocomplete from "@material-ui/lab/Autocomplete";

const AutocompleteEditor = forwardRef(
  ({ fieldToSave, fieldToShow, textFieldProps, options, ...props }, ref) => {
    const [value, setValue] = useState("");

    useImperativeHandle(ref, () => {
      return {
        getValue: () => {
          return value;
        },
        afterGuiAttached: () => {
          setValue(props.value);
        },
      };
    });

    const tranformValue = (value, fieldtosave) =>
      Array.isArray(value)
        ? value.map((v) => v[fieldtosave] || v)
        : value[fieldtosave];

    function onChangeHandler(e, value) {
      setValue(value ? tranformValue(value, fieldToSave) : null);
    }

    return (
      <MuiAutocomplete
        style={{ padding: "0 10px" }}
        options={options}
        getOptionLabel={(item) => {
          return typeof item === "string" || typeof item === "number"
            ? props.options.find((i) => i[fieldToSave] === item)[fieldToShow]
            : item[fieldToShow];
        }}
        getOptionSelected={(item, current) => {
          return item[fieldToSave] === current;
        }}
        value={value}
        onChange={onChangeHandler}
        disableClearable
        renderInput={(params) => (
          <MuiTextField
            {...params}
            {...textFieldProps}
            style={{ padding: "5px 0" }}
            placeholder={"Select " + props.column.colId}
          />
        )}
      />
    );
  }
);

export default AutocompleteEditor;

IGNORE THE AUTOCOMPLETE PART IF ITS CONFUSING, ITS NOT IMPORTANT FOR UNDERSTANDING useImperativeHandler

So To explain what the code does. The value of the above component is set by Autocomplete by the user, but ag-grid table also needs the value as it needs to update the value in corresponding cell.

It uses a ref internally that it passes to the customCellEditor. The useImperativeHook then tells ag-grid to use the value from the state of the component whenever getValue is called (it is called when the cell needs to display the value)

dracarys
  • 1,071
  • 1
  • 15
  • 31