in ref callback, ref is someitimes not part of the DOM yet
See original GitHub issueNot 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:
- Created 7 years ago
- Reactions:2
- Comments:25 (11 by maintainers)
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 thecomponentDidMount()
lifecycle event to initialize your swipe system.I would definitely avoid invoking DOM side effects from within render like this - instead, use
componentDidUpdate()
/componentDidMount()
:Ideally, you want
render()
to be a pure VDOM pipeline, it should never trigger any external effects.