简体   繁体   中英

How to use React useRef hook with typescript?

I am creating a reference using the new useRef hook

const anchorEl = React.useRef<HTMLDivElement>(null)

And using like

<div style={{ width: "15%", ...flexer, justifyContent: "flex-end" }}>
    <Popover
        id="simple-popper"
        open={open}
        anchorEl={anchorEl}
        onClose={() => {
          setOpen(false)
        }}
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'center',
        }}
        transformOrigin={{
          vertical: 'top',
          horizontal: 'center',
        }}
    >
        <Typography>The content of the Popover.</Typography>
    </Popover>
</div>
<div ref={anchorEl} >
      ...

but I get this error

TS2322: Type 'MutableRefObject<HTMLDivElement>' is not assignable to type 'HTMLElement | ((element: HTMLElement) => HTMLElement)'.
  Type 'MutableRefObject<HTMLDivElement>' is not assignable to type '(element: HTMLElement) => HTMLElement'.
    Type 'MutableRefObject<HTMLDivElement>' provides no match for the signature '(element: HTMLElement): HTMLElement'.
Version: typescript 3.2.2, tslint 5.12.0

anchorEl variable is ref object, an object that has only current property. It's unknown how Popover works but, but it expects an element as anchorEl prop, not a ref.

It should be:

<Popover
    id="simple-popper"
    open={open}
    anchorEl={anchorEl.current}

If <Popover and <div ref={anchorEl} > are siblings like it's shown, a ref won't be ready to use at the moment when it's passed as a prop. In this case a component needs to be re-rendered on mount:

const [, forceUpdate] = useState(null);

useEffect(() => {
  forceUpdate({});
}, []);

...

   { anchorEl.current && <Popover
        id="simple-popper"
        open={open}
        anchorEl={anchorEl.current}
        ...
   }
   <div ref={anchorEl} >

In case <div ref={anchorEl} > doesn't have to be rendered to DOM, it could be

   <Popover
        id="simple-popper"
        open={open}
        anchorEl={<div/>}

The necessity to render a component twice and use forceUpdate workaround suggests that this could be done in a better way. The actual problem here is that Popover accepts an element as a prop, while accepting refs is common in React.

At this point ref object has no benefits.Ref callback can be used with useState instead, state update function is callback that receives new state as an argument and it doesn't cause additional updates if it receives the same state (DOM element):

const [anchorEl, setAnchorEl] = useState<HTMLDivElement>(null);

...

   { anchorEl && <Popover
        id="simple-popper"
        open={open}
        anchorEl={anchorEl}
        ...
   }
   <div ref={setAnchorEl} >

You can use MutableRefObject type from 'react'

import { MutableRefObject } from "react"

const anchorEl: MutableRefObject<HTMLDivElement> = React.useRef(null);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM