React: ref set to null on every render

Created on 17 Oct 2017  路  7Comments  路  Source: facebook/react

Do you want to request a feature or report a bug?

Possible bug

What is the current behavior?

ref callbacks are always passed null once before subsequently being passed the reference

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://jsfiddle.net or similar (template for React 16: https://jsfiddle.net/Luktwrdm/, template for React 15: https://jsfiddle.net/hmbg7e9w/).

With the attached code sample, the following life cycle functions and ref callbacks are executed:

null-ref-example.zip

/* Initial Render */
App render
MyApp render
MyPortal render
MyApp ref set to:  MyApp {鈥
MyPortal ref set to:  MyPortal {鈥

/* Second Render */
App will update
App render
MyApp will update
MyApp render
MyPortal will update
MyPortal render
MyApp ref set to:  null
MyPortal ref set to:  null
MyApp did update
MyApp ref set to:  MyApp {鈥
MyPortal did update
MyPortal ref set to:  MyPortal {鈥
App did update

What is the expected behavior?

I wasn't expecting all refs to be set to null on each render. (although it gets set again shortly thereafter)

If this is expected behaviour I didn't see it in the documentation...

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

React 16, MacOS, Chrome 61 & Safari 11.

Most helpful comment

All 7 comments

Ahh! Thanks @gaearon , I figured this must have been somewhat by design.

It makes sense too. It's similar to how PureComponent works with inline functions.

I assumed this was specific to React 16 since this issue only manifested itself in react-bootstrap after the upgrade.

Thanks for the link to the previous issue and the caveats. Super helpful!

@gaearon How can we solve this in a functional component? In other words because it's functional i cannot define the ref callback as a "bound" method.

@joepuzzo You can use the useCallback hook to create a stable Identify, probably better,

const [ref, attachRef] = useState(null)

return <div ref={attachRef} />

or already wrapped up: https://github.com/react-restart/hooks/blob/master/src/useCallbackRef.ts

Hmm I like that.. however i need to set two refs in the function and just calling the setter wont be enough for me.

To elaborate i maintain a library where i internally need to access the ref but also want to allow the user to access the ref. In order to achieve that i need to use a ref callback that looks somthing like this

(ref) => {
  userRef.current = ref;
  internalRef.current = ref;
}

I don't get at all the part about "React needs to clear the old ref and set up the new one", but for me the workaround that did the trick was to replace ref={el => {...}} with ref={React.useMemo(() => el => {...}, [])}.

Was this page helpful?
0 / 5 - 0 ratings