React Why is my binded method being called in render? - reactjs

Here in my constructor:
constructor(props) {
super(props);
this.moveGroup = this.moveGroup.bind(this);
}
And im trying to pass this method to a custom component:
render() {
return(
<Group
moveGroup={this.moveGroup}
/>
)
}
Why is that this automatically calls the method?
I've tried a lot of combinations of binding and its not working. I've also read that you shouldn't bind in render, but I can't get this to work without doing that. Every blog I've read tells you to bind in the constructor

Figured it out.
In my Group's render, it was:
onClick={this.props.moveGroup(start, finish)}/>}
All I had to do was bind it:
onClick={() => this.props.moveGroup(start, finish)}/>}
edit: It seems that I was calling the method itself, so I had to bind it to a function so that it wouldn't be called automatically

Related

bind(this) in ReactComponent.render() method

I have a quite big React.Component with more than ten bind(this) calls in its constructor.
I don't think .bind(this) in a constructor gives any help to understand my code especially when reading the code inside of render().
So, I came up with the following idea, however, do not find how to achieve this.
render() {
if (this.methodToBind.getThis() === this) {
this.methodToBind = this.methodToBind.bind(this);
}
}
Is there any possible way I can get this of a method (getThis() from the example above)?
If yes for the above, is it a good practice to do this?
rather then doing this,
constructor () {
super();
this.myFunc = this.myFunc.bind(this);
}
myFunc () {
// code here
}
You can do something like this.
constructor () {
super();
// leave the binding, it's just not what the cool kids do these days
}
myFunc = () => {
// see what I did here with = () => {}
// this will bind your `this` with it's parent
// lexical context, which is your class itself, cool right. Do this!
}
For a reference have a look at the MDN documentation for Arrow Functions
Where to Bind This?
When you create a function in a Class Based Component in React.js you must bind this in order to call it from the render method. Otherwise the function will not be in scope.
There are a few ways to do this.
Never bind this in the render method. Binding this in the render method will cause React to create a new function every time your Component is rerendered. This is why we most commonly bind in the constructor.
Bind in the constructor. By binding in the constructor, you can call your function in the render method by using this.FunctionName();
Example Bind This
Class MyClass extends Component {
constructor(props) {
super(props);
this.FunctionName = this.FunctionName.bind(this);
}
myFunc () {
// code here
}
render() {
this.FunctionName();
return(
<div>
...
</div>
);
}
}
User fat arrow functions instead of traditional function definitions. Fat arrow functions lexically bind the this value. So you do not have to add bind to the function in the constructor when you use the fat arrow function in the class.
Important - Fat arrow functions are not always available to use in a React class. Depending on how you setup React. You might have to install,
babel-plugin-transform-class-properties
Then add it to your .bablerc file like this,
{
"plugins": [
"transform-class-properties"
],
"presets": [
"react"
]
}
Example Fat Arrow
Class MyClass extends Component {
myFunc = () => {
// code here
}
render() {
this.FunctionName();
return(
<div>
...
</div>
);
}
}
Summary
Never bind a function in the render.
Always bind in the constructor when using a traditional function
this is automatically available on the function when using a fat arrow function.
Not sure.
I am usually doing something like this:
onClick={this.handleClick.bind(this)}
or:
onClick={e => this.handleClick(e)}

Bind method to react state changes

Given the code below, I would like the transform() method to run anytime this.props.code changes.
class Editor extends Component {
render() {
return (
<div id="pseudo-editor" />
);
}
transform() {
var editor = ace.edit("pseudo-editor");
editor.setValue(this.props.code,1);
}
}
I am using react-redux and the state to props binding works as intended.
But Im not quite sure how to approach method binding. I guess its not an alternative to fit my JS code editors API calls inside the render method. Problably a simple solution to this one but could not find an example of which pattern to use here. Thankful for any help.
Use componentWillReceiveProps lifecycle method, it will get called whenever any change happens to props values, check the previous and nextProps values if they are not same call the transform method.
Like this:
componentWillReceiveProps(nextProps){
if(this.props.code != nextProps.code)
this.transform();
}
As per DOC:
componentWillReceiveProps() is invoked before a mounted component
receives new props. If you need to update the state in response to
prop changes (for example, to reset it), you may compare this.props
and nextProps and perform state transitions using this.setState() in
this method.

React event without binding this

I'm currently in the process of learning React and I've come across something that seems weird in React's Getting Started guides.
I'm currently reading this section.
There's this code sample: https://codepen.io/gaearon/pen/QKzAgB?editors=0011
It showcases conditional rendering, that's not the point of my question though.
When they pass the HandleLogout/LoginEvent, they just pass this.HandleLoginEvent, without binding or using arrow functions, yet this code works perfectly, how does it work?
The piece of code I'm talking about is this:
let button = null;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
In the previous section of the guides they explicitly state you have to use some method to bind the "this" in order for "this" not to be undefined when called from a child component, which makes sense.
Yet here "this" is somehow magically bound, how is it done?
Thanks, Avi.
EDIT: As Ori kindly pointed out, there's a bind call I've missed, problem solved :)
There are multiple ways to handle React binding pattern:
Bind in render
render() {
return (
<LogoutButton onClick={::this.handleLogoutClick} />
{/* or */}
<LogoutButton onClick={this.handleLogoutClick.bind(this)} />
)
}
Bind in constructor
As shown in the codepen, which explains why you don't see binding in render.
constructor(props) {
super(props)
this.handleLoginClick = this.handleLoginClick.bind(this)
// or
this.handleLoginClick = ::this.handleLoginClick
}
Use arrow function
When you use arrow function to declare handleLogoutClick, the function uses lexical binding.
Normally in JS, the value of this is determined by how a function is called. But with ES6 arrow function, we are able to create function that behaves differently -
it retains the this value of the enclosing lexical context, now we don't even have to call bind!
handleLogoutClick = () => {
this.setState({isLoggedIn: false});
}
// and you can simply
onClick={this.handleLogoutClick}
Personally I definitely prefer arrow function, as it produces cleaner code, and I don't have to write that constructor just to bind stuffs. I can simply do:
class LoginControl extends React.Component {
state = {isLoggedIn: false}
//... other stuffs ...
}
As for binding in render (or arrow function inside render), you should always avoid that.
When working with PureComponent, binding in render will cause unnecessary re-rendering.
Why Arrow Functions and bind in React’s Render are Problematic
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {isLoggedIn: false};
}
When you do it this way you avoid forgetting to bind them when passing them all over the place.

What is the best and most efficient way to bind callbacks in ReactJS? In the constructor or in the render method or as a property initializer?

Say I have a function in the Parent component that I want to use as a callback for the Child component. Which way is better?
render() {
return (
<Child handleClick={this.handleClick.bind(this)} />
)
}
or
constructor() {
super();
this.handleClick = this.handleClick.bind(this);
}
According to this eslint, it is much better to do so in the constructor because the render() method may be called multiple times. This makes perfect sense to me.
However, this just means that the bound function ends up being a property on each and every instance. Thus defeating the entire purpose of the prototype.
I do know about the property initializers:
handleClick = () => {
// do stuff
}
But it looks this syntax is no where close to being agreed upon for ES2017 (or whatever the next one might be). For this reason, I'm afraid to use this syntax as it might never make it into the language.
So, having said all that, what is the best way to go about this?
Although all options you and other people in comments have said do definitely work, I would go for Airbnb's React styleguide one:
✓ Binding on the constructor
constructor(props) {
super(props);
this.foo = this.foo.bind(this);
}
✓ ES7 binding on constructor is also a good option (though keep in mind that it is still a proposal)
constructor(props) {
super(props);
this.foo = ::this.foo;
}
What about the other options?
✖ Binding on render
render() {
return <button onClick={this.handleClick.bind(this}>...</button>
}
Rebinded on every re-render, not to say that if you have two elements that use the same function, you will have to choose whether to leave one without binding or binding both (which would be ugly or more inefficient).
✖ Arrow function (not binding)
render() {
return <button onClick={(e) => this.handleClick(e)}>...</button>
}
You are going through one more function when there is no need to.

In componentDidUpdate refs is undefined

I want to use Chart.js on my website. As you can see title, I'm using React.js. To use Chart.js, I need the canvas and context like this:
let context = document.getElementById('canvas').getContext('2d');
let chart = new Chart(context, ...);
so I design the component like this:
export function updateChart() {
let context = this.refs.chart.getContext('2d');
let chart = new Chart(context ,... );
...
}
export default class GraphChart extends React.Component {
constructor() {
super();
updateChart = updateChart.bind(this);
}
componentDidMount() {
updateChart();
}
render() {
return <canvas ref="chart" className="chart"></canvas>;
}
}
as you can see, I exported two things, update chart function and GraphChart class. Both will using in parent component like this:
import { updateChart } from './GraphChart';
import GraphChart from './GraphChart';
class Graph extends React.Component {
...
someKindOfAction() {
// update chart from here!
updateChart();
}
render() {
return (
<div>
<SomeOtherComponents />
<GraphChart />
</div>
);
}
}
then Parent class using exported updateChart function to update chart directly. It was working, but only first time. After unmount and mount the GraphChart component, it's refs are just empty.
Why refs is empty? And If I did wrong way, how can I get canvas context for initialize Chart.js?
Object refs is undefined, because this is not what you think it is. Try logging it.
The function you’re exporting is not bound to this of your component. Or perhaps it is, but to the last created instance of your component. You can never be sure that’s the mounted instance. And even if you are, you can not use multiple instances at the same time. So, I would dismiss this approach entirely.
Other than that, providing the function to alter some component’s state is exactly the opposite of what’s React is trying to accomplish. The very basic idea is that the component should know to render itself given some properties.
The problem you are trying to solve lies in the nature of Canvas API, which is procedural. Your goal is to bridge the gap between declarative (React) and procedural (Canvas) code.
There are some libraries which do exactly that. Have you tried react-chartjs? https://github.com/reactjs/react-chartjs
Anyways, if you’re wondering how the hell should you implement it the “React way”, the key is to declare properties your component handles (not necessarily, but preferably), and then to use component lifecycle methods (e.g. componentWillReceiveProps and others) to detect when properties change and act accordingly (perform changes to the canvas).
Hope this helps! Good luck!

Resources