user2953989
user2953989

Reputation: 2979

React: this.function is not a function

I'm getting the error this.updateCSSAnimation is not a function, but i'm unsure why as I have bound it in my constructor. I have tried this.updateCSSAnimation with and without parenthesis but neither work.

import React from 'react'

class ScrollBG extends React.Component {
  constructor(props) {
    super(props)

    this.updateCSSAnimation = this.updateCSSAnimation.bind(this)
  }

  componentDidMount () {
    document.addEventListener('scroll', this.handleScroll)
  }

  componentWillUnmount () {
    document.removeEventListener('scroll', this.handleScroll)
  }

  handleScroll () {
    this.scroll = window.ScrollY

    this.globe = document.querySelector('.globe')
    this.map = document.querySelector('.map')

    this.updateCSSAnimation()
  }

  updateCSSAnimation () {
    const scroll = this.scroll

    this.globe.style.bottom = 0 + 200 * (scroll / 250) + 'px'
    this.map.style.width = 68 + (scroll / 50) + 'rem'
  }

  render () {

    return (
      <section className='map'>
        <div className='globe'>
         stuff
        </div>
      </section>
    )
  }
}

export default ScrollBG

Upvotes: 2

Views: 138

Answers (3)

Andrii Golubenko
Andrii Golubenko

Reputation: 5179

In your case this in handleScroll - is a reference to document. document does not have updateCSSAnimation function. Instead of updateCSSAnimation you need to bind handleScroll function:

constructor(props) {
    super(props)

    this.handleScroll = this.handleScroll.bind(this)
  }

Upvotes: 4

DrBojingle
DrBojingle

Reputation: 11

It's because of

 document.addEventListener('scroll', this.handleScroll)

and

document.removeEventListener('scroll', this.handleScroll)

your handleScroll function is being called in a different context so the use of this inside that function is not referring to ScrollBG.

if you bind(this) to handleScroll it should work fine.

ie

document.addEventListener('scroll', this.handleScroll.bind(this))

Depending on your env, you might also be able to take advantage of arrow functions by doing this:

handleScroll = () => {
  this.scroll = window.ScrollY

  this.globe = document.querySelector('.globe')
  this.map = document.querySelector('.map')

  this.updateCSSAnimation()
}

Arrow functions automatically bind(this) to a function but in order to take advantage of them in classes in the way I've described above, you'll need to have class properties enabled in your build env. Here's a simple example of context in JS with a class that has an arrow function and a regular method.

Reference:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

https://blog.pragmatists.com/the-many-faces-of-this-in-javascript-5f8be40df52e

Upvotes: 0

Darpan Rangari
Darpan Rangari

Reputation: 1570

you are calling this.updateCSSAnimation() from handleScroll which is why you are facing issue.

Simply bind this.handleScroll = this.handleScroll.bind(this) inside constructor

hope this helps, happy coding!!!

Upvotes: 1

Related Questions