MarcL
MarcL

Reputation: 3593

No need to bind functions in React Component Classes anymore?

I just noticed, that if I define normal class component functions, I do not need to bind these anymore inside the class constructor... (so even if I dont use ES6 public class field syntax), I can just normally pass those functions to my event handlers via onClick={this.someFunction} without the need to bind them to my class beforehand and it does not throw me an error when the native DOM event (or synthetic event in React's case) is executed. And it also does not matter if I use an arrow function as my event handler or just pass the function reference...

is this a new feature to React? I think some months ago, this feature was not there yet..

EDIT: here is some code example, its a simple newsfeed api app, where index has a ListItem subcomponent thats passed the click handler...

import {React, Component, fetch, API_KEY, BASE_URL} from '../config/config';
import ListComponent from '../components/ListComponent';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/core/styles';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import { List } from '@material-ui/core';


const useStyles = makeStyles(theme => ({
  root: {
    width: '100%',
    height: 400,
    maxWidth: 360,
    backgroundColor: theme.palette.background.paper,
  },
}));

export default class index extends Component { 
    constructor(props) {
        super(props);
        this.state = {
            news: this.props.news
        }
    }   


    static async getInitialProps() {
        let querystring = `${BASE_URL}top-headlines?q=sex&fsortBy=popularity&apiKey=${API_KEY}`;
        console.log(querystring);
        let news =  await fetch(querystring);
        news = await news.json();
        //console.log("NEWS:",news.articles);
        return {
            news: news.articles
        }
    }

    getOutput (e) {
        console.log("Item ",e," was clicked!");
    }

    render() {
        return (
            <div>
                {                    
                   this.state.news.map((news,index) => (
                    // <ListItem button 
                    // key={index} 
                    // onClick={e => this.getOutput(e)}>
                    // <ListItemText primary={`${news.title}`} />
                    // </ListItem>
                    <ListComponent 
                    index = {index}
                    news = {news}
                    clicked = {this.getOutput}
                    />
                    )
                   )

                }
            </div>
        )
    }
}

Here is the List subcomponent:

import React from 'react'    

export default function ListComponent({index,clicked,news}) {
    return (
        <li key={index} onClick ={clicked}>
            {
                news.title
            }
        </li>
    )
}

I just tested it, and it worked! Note: This is a Next.js example, but I have tested it in a normal React-app (created with create-react-app), too and it worked with same kind of example... when I click a list item I get console output:

Item  Class {dispatchConfig: {…}, _targetInst: FiberNode, nativeEvent: MouseEvent, type: "click", target: li, …}  was clicked!

Upvotes: 1

Views: 2757

Answers (2)

Sagiv b.g
Sagiv b.g

Reputation: 31024

This is not related to react but how JavaScript's class and this works.

In your example you are not getting errors because you are not doing anything wrong. Although when you want to call this.setState or reference anything via this you may get an error or unexpected results because this will not reference what you think it will, it will reference the element that triggered the event.

Why class field with arrow functions "solve" the problem without hard binding the this? because they way they "handle" the this context, which they actually don't do anything. meaning, what ever the this reference in the wrapping execution context, that's the reference you will get inside an arrow function.

By the way, there is a difference between a class field functions and class methods is that class methods are created on the prototype and fields are created on the instance.

I've made a simple flow chart that may help understand what is this referencing to for a given context (always top to bottom, order matters)

enter image description here

Upvotes: 1

SimoMatavulj
SimoMatavulj

Reputation: 584

This is not a new feature of React. You can access any function or property from within class without binding. The reason why you do binding( or declare arrow function) is to connect local this to global context so it can refer to the class(parent function). Try using e.g this.props inside getOutput function and you will get an error.

Upvotes: 1

Related Questions