Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forwarding multiple ref in typescript

I'm trying to forward an object of ref in typescript, but I'm facing an issue to correctly type them.

This are my refs and how I pass them inside my component.

const storyRef = useRef<HTMLElement>(null);
const parcoursRef = useRef<HTMLElement>(null);
const projectRef = useRef<HTMLElement>(null);

const refs = useRef({ storyRef, parcoursRef, projectRef });

...
...

<Navbar ref={refs} setShowModal={setShowModal} />

Inside my component I type them this way:

const Navbar = React.forwardRef<
    React.MutableRefObject<{
        storyRef: React.RefObject<HTMLElement>;
        parcoursRef: React.RefObject<HTMLElement>;
        projectRef: React.RefObject<HTMLElement>;
    }>,
    ModalProps
>(({ setShowModal }, ref) => {

This is the error I have:

Type 'MutableRefObject<{ storyRef: RefObject; parcoursRef: RefObject; projectRef: RefObject; }>' is not assignable to type 'Ref<MutableRefObject<{ storyRef: RefObject; parcoursRef: RefObject; projectRef: RefObject; }>> | undefined'. Type 'MutableRefObject<{ storyRef: RefObject; parcoursRef: RefObject; projectRef: RefObject; }>' is not assignable to type 'RefObject<MutableRefObject<{ storyRef: RefObject; parcoursRef: RefObject; projectRef: RefObject; }>>'.

like image 642
samuel potter Avatar asked Oct 12 '25 10:10

samuel potter


1 Answers

React does not directly support Forwarding multiple ref in typescript. However fear not, there is a real solution called the useImperativeHandle hook. You can also create unlimited refs to child elements and even functions.

My example has a child component which shows you can easily forward refs to:

  • Any html element
  • Functions

All with typescript goodness.

Fully working example:

Edit affectionate-ben-q4ox51

//Child Component 

//Create your ref types here
export type RefHandler = {
  pressAlert: () => void;
  inputRef: RefObject<HTMLInputElement>;
};

const Child = forwardRef<RefHandler, Props>((props, ref) => {
  const submitRef = useRef<HTMLButtonElement>(null);
  const inputRef = useRef<HTMLInputElement>(null);

  //Initialise your refs here
  useImperativeHandle(ref, () => ({
    inputRef: inputRef,
    pressAlert: () => submitRef?.current?.click()
  }));

  return (
    <div>
      <p>Child Component</p>
      <input type="text" value="lorem ipsum" ref={inputRef} />
      <br />
      <button onClick={() => alert("Alert pressed")} ref={submitRef}>
        Alert
      </button>
    </div>
  );
});
//Parent 
export default function Parent() {
  const childRef = useRef<RefHandler>(null);

  return (
    <>
      <p>Parent</p>
      <button
        onClick={() => {
          alert(childRef?.current?.inputRef?.current?.value);
        }}
      >
        Read child input
      </button>
      <button onClick={() => childRef?.current?.pressAlert()}>
        Press child button
      </button>
      <hr />
      <Child ref={childRef} />
    </>
  );
}

like image 177
rottitime Avatar answered Oct 14 '25 23:10

rottitime