1

How can I bind "this" with setState callback. Does react allows it?

this.state = {
    selectedId: null,
}

//On click of some list item as

<ListGroup.Item 
  action href="" 
  key={id}
  onClick={()=>
    this.setState({selectedId: id.ID}), () => console.log(this.state.selectedID)
  }
>
  LIST ITEM
</ListGroup.Item>)
ravibagul91
  • 20,072
  • 5
  • 36
  • 59
Meana
  • 65
  • 1
  • 9

3 Answers3

2

You need to bind onClick and not setState so that when bound onClick calls setState, it can 'supply' this in order to make the call. In React class components handlers like onClick are bound in constructor:

class BindingExample extends React.Component {
  constructor(props) {
    super(props);
    this.state = { selectedId: null }
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState( prevState => (...prevState, { selectedId: id.ID }),
                   () => console.log(this.state.selectedID)
                 );
  }

  render() {
    return (
      <>
        <button onClick={this.handleClick}>
         Click me
        </button>
      </>
    );
  }
}

If onClick was implemented as a fat arrow function

handleClick = () => {
   this.setState( prevState => (...prevState, { selectedId: id.ID }),
                   () => console.log(this.state.selectedID)
                );
}

then there wouldn't be any need to bind it because fat arrow functions always capture this. As a sidenote, class components are currently out of fashion in React.

winwiz1
  • 2,906
  • 11
  • 24
  • why fat arrows always capture this ? – Afraz Ahmad Sep 26 '19 at 13:13
  • @AfrazAhmad Fat arrows always capture `this` by design. In other words it's a feature of ES6. – winwiz1 Sep 26 '19 at 13:16
  • No, its because fat arrow functions are moved inside constructor during compile time. its like you are defining a function inside constructor which has 'this' in its parent scope. – Afraz Ahmad Sep 26 '19 at 13:18
  • @AfrazAhmad "No, its because fat are moved inside constructor during compile time" Fat arrow functions capture `this` even when there are no classes and no constructors around. In which case `this` is captured from execution context. It's by design and this is a fundamental feature. What happens at compilation time is a technicality chosen by authors of the compiler to implement the design requirement. – winwiz1 Sep 26 '19 at 13:28
  • @AfrazAhmad: You are mixing up two different things: Public class fields (which are syntactic sugar for assigning properties to `this` in the constructor) and arrow functions. Public class fields are often used with arrow functions to achieve the effect you mentioned, but only because arrow functions resolve `this` this way, not the other way round. – Felix Kling Sep 26 '19 at 13:50
  • @winwiz1 I still face this "Expected an assignment or function call and instead saw an expression no-unused-expressions" which I guess is more about the syntax and "Uncaught TypeError: Cannot read property 'handleClick' of undefined" – Meana Sep 26 '19 at 14:11
  • And yes I have class Component – Meana Sep 26 '19 at 14:12
  • @Meana When getting several errors, a good approach is to focus on the first one and forget the rest for a moment. Regarding "Expected an assignment ...", yes it's syntax, maybe related to brackets and curly braces. Hard to tell without seeing your code, can it be [this](https://stackoverflow.com/questions/53013437/expected-assignment-or-function-call-no-unused-expressions-reactjs) – winwiz1 Sep 26 '19 at 15:13
  • @winwiz1 Ok it works...I figured out my mistake. At some point in my code while looping through my data array, I was using regular function instead of callback function. So in case, the reference for "this" was being lost. May be , next time should post complete code. Thanks alot anyways!! – Meana Sep 26 '19 at 15:33
  • fat arrow functions always capture this. THIS statement is **wrong**. Actually what happens is that arrow function doesn't capture anything, and it skipped this. That's why the outside this is leaked in. – windmaomao May 17 '21 at 21:20
1

You have implemented callback of setState in a wrong way here,

onClick={()=>
  this.setState({selectedId: id.ID}), () => console.log(this.state.selectedID)
}

Your setState is ended here itself,

this.setState({selectedId: id.ID})   //This is complete setState

You if want to add callback to setState, you need to write it inside of setState as,

onClick={()=>
  this.setState({
     selectedId: id.ID
  }, () => console.log(this.state.selectedId)   //This is callback
  ) //end of setState
} //end of onClick

Note: You are printing this.state.selectedID, but in state your have selectedId.

Demo

ravibagul91
  • 20,072
  • 5
  • 36
  • 59
0

You don't need to bind this when you run an inline callback arrow function.

The issue with your code is that you have 2 functions

onClick={()=> this.setState({selectedId: id.ID})
//// this line is wrong
, () =>
////
console.log(this.state.selectedID)}

Change your onClick code to this:

onClick = {() => {
        this.setState({selectedId: id.ID}); 
        console.log(this.state.selectedID)
}}

Also this seems wrong.

this.state = {
    selectedId: null,
}

Change it to this:

state = {
    selectedId: null,
}

Hope this helps.

Dilshan
  • 2,797
  • 1
  • 8
  • 26
Shmili Breuer
  • 3,927
  • 2
  • 17
  • 26