2

I'm working on React component called ProjectCard that holds two divs. The second div has a dropdown, and I want to highlight the entire card when the user hovers over the card or the dropdown has been clicked. I used Radium for adding hover functionality to previous components, but in order to incorporate this new logic for highlighting, I tracked isActive and isLocked in the card state. For example, I toggle isActive when mouse enters or leaves the component in the following function. (I bound toggleActive in the constructor)

toggleActive () {
  console.log(this);
  this.setState({
    isActive: !this.state.isActive
  });
}

However, I got an error that I could not set state before the component was mounted. Poking around a bit and logging this in various functions, it seemed like it was a problem with Radium. I used the Radium wrapper in my export, like so: export default Radium(ProjectCard);, and the above toggleActive logged ProjectCard as this, while componentDidMount logged RadiumEnhancer(ProjectCard) as this. A Radium-less workaround would be to use a HoC, but I thought I could maybe fix this by adjusting the scope I bound this, so I moved the function binding to componentDidMount, as shown below. (Using arrow functions automatically bound scope like calls from the constructor)

constructor (props: Props) {
  super(props);
  this.state = {
    isActive: true,
    isLocked: false
  };
}

componentDidMount() {
  console.log(this);
  this.onClick = this.onClick.bind(this);
  this.toggleLock = this.toggleLock.bind(this);
  this.toggleActive = this.toggleActive.bind(this);
  console.log("mounted, functions bound");
  //console.log(this.toggleActive);
  this.toggleActive();
  //manual fix, stackoverflow this.
}

However, binding in componentDidMount and hovering over the component caused no change and toggleActive to log this as undefined. No luck, the fix didn't appear to work.

However, while trying to debug, I manually invoked toggleActive (as shown above) and it logged RadiumEnhancer(ProjectCard) (the scope I wanted) and miraculously, hover functionality started working (and the other functions also got the correct scope).

My questions are:

  • Was the improper scope/Radium causing the setState error? There were no async operations in the code other than setState.
  • If so, is this fix legitimate? Why didn't it work after I changed the scope I bound this to?
  • Why did manually calling toggleActive give all the functions the right this and scope?

Thank you! Here is a pastebin for relevant code: https://pastebin.com/MRKw2APw

Joel Ye
  • 63
  • 1
  • 4
  • Try to use arrow function definition `componentDidMount = () => {}` this way `componentDidMount` will use as context `this`. – Aren Hovsepyan Dec 22 '17 at 00:46
  • Using arrow notation defaults this to the unenhanced ProjectCard, so that doesn't work, thanks for the suggestion though! – Joel Ye Dec 22 '17 at 03:42

1 Answers1

0

If you delete everything in your render function and just render a simple p tag, you will see 'this' and 'toggleActive' is not undefined. Double check your render function.

arrra
  • 31
  • 6
  • I reduced my render function to the following and hovering says "cannot setState of undefined" (where `this` is undefined). Leaving binding functions in componentDidMount, I get this error both with and w/o arrow notation. Render is just `return (
    `
    – Joel Ye Dec 22 '17 at 03:48