question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

in ref callback, ref is someitimes not part of the DOM yet

See original GitHub issue

Not sure if this is supposed to work this way or not, but it seemed odd to have the ref only work sometimes.

I’ve got a div with a ref callback, and using that ref I wanted to get it to initialize swipejs which requires a width from the ref’s children. However, I found that the ref is sometimes not yet part of the DOM. So when it tries to access the width on the page within the ref callback sometimes the width is zero, and sometimes it is my expected width of ~1000px. I dug in, and saw the width being 0, document.querySelectorAll('.swipe') being [], and ref.parentNode being null during the times it wasn’t working. Other times those all returned expected results of the width, the ref, and the parent.

Didn’t have time to dig in too deep, but I did find a workaround by just grabbing the ref in the callback, and then using that ref in the componentDidMount lifecycle hook.

Here’s my code with the working workaround

import { h, Component } from 'preact'
import SwipeJS from 'swipejs'

class Example extends Component {
  constructor (props) {
    super(props)
    this.state = {
      activeIndex: 0
    }
  }

  componentDidMount() {
    const ref = this.swipeRef
    if (ref) {
      this.swipe = this.swipe || new SwipeJS(ref)
    }
  }

  componentWillUnmount () {
    if (this.swipe) {
      this.swipe.kill()
      this.swipe = false
    }
  }

  initializeSwipe (ref) {
    if (!ref) {
      // ref is called on removal with null element
      return
    }
    this.swipeRef = ref
  }

  render (props, state) {
    return (
        <div className='swipe' ref={ref => this.initializeSwipe(ref)}>
          <div className='swipe-wrap'>
            <div></div>
            <div></div>
          </div>
        </div>
    )
  }
}

export default Example


Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:2
  • Comments:25 (11 by maintainers)

github_iconTop GitHub Comments

4reactions
developitcommented, Dec 30, 2016

Hi there - preact doesn’t guarantee refs are called after parent elements are mounted. Instead (and in general in React codebase), I recommend instead using the ref callback to store a reference to the created element, then using the componentDidMount() lifecycle event to initialize your swipe system.

3reactions
developitcommented, Apr 22, 2017

I would definitely avoid invoking DOM side effects from within render like this - instead, use componentDidUpdate() / componentDidMount():

componentDidMount() {
  if (this.state.open) {
   this.attachListeners();
  }
}

componentDidUpdate(prevProps, prevState) {
  if (this.state.open && !prevState.open) {
    this.attachListeners();
  }
}

Ideally, you want render() to be a pure VDOM pipeline, it should never trigger any external effects.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Refs and the DOM - React
React will call the ref callback with the DOM element when the component mounts, and call it with null when it unmounts. Refs...
Read more >
Ref callback attribute is not working as expected
The first on has a reference to the callback function. The second one has an arrow function declared as the value. The first...
Read more >
React Callback Refs — a Complex Case | by E.Y. - Medium
If the ref callback is defined as an inline function, it will get called twice during updates, first with null and then again...
Read more >
Avoiding useEffect with callback refs - TkDodo's blog
ref is a reserved property on build-in primitives, where React will store the DOM node after it was rendered. It will be set...
Read more >
Understanding Callback Refs - JavaScript in Plain English
React utilizes a virtual DOM which prevents the use of querySelectorAll() or getElementById() methods to imperatively modify specific nodes.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found