简体   繁体   中英

Binding in constructor vs arrow function in d3 callbacks + React

I'm working with d3 (v3)'s brush feature right now and ran into a situation where binding in the constructor works, but using a class function doesn't. My .babelrc is set up for class functions with "presets": ["flow", "latest", "stage-2", "react"] and I've gotten arrow functions working in the rest of the code, so it's not a matter of transpilers.

Code in question:

    this.brush = d3.svg.brush()
        .x(xScale)
        .on("brushend", this.changeDates)

    const brushGroup = d3.select(this.node).append("g")
        .attr("class", "brush")
        .call(brush)

If I bind change dates in the constructor as follows, I find that this in the function changeDates is the React Component ExampleSVG , which is the desired behavior.

class ExampleSVG extends Component {
    constructor(props) {
        super(props)
        this.changeDates = this.changeDates.bind(this)
    }   

    changeDates() {
        console.log(this) //ExampleSVG {props: {...}, context: {...}}
    }

    ...d3 stuff
}

However, if I try binding via the arrow function, this becomes the function svg group.

class Example extends Component {
    changeDates = () => {
        console.log(this) //<g class="brush" ... />
    }

    ...d3 stuff
}

Why is the arrow function not binding (once again, not a transpilation issue, I have plenty of binding arrows in my code)? There's probably something about d3/this that I'm missing here, but I want to figure this out! Is it call ? In which case, what does call do such that it can override arrow binding?

An arrow function doesn't have its own this .

With non-arrow functions passed to D3 selection methods (such as .attr() , .on() ), D3 uses function.apply() to set this as the element being modified, which is why it isn't the window (the globally scoped this or, if it is not this, the this whose scope includes the arrow function).

But, as arrow functions can't have their own scoped this , this will refer to the whichever this has a scope that includes the arrow function.

So, this will be different in a typical function as compared to an arrow function. Hence, why you shouldn't use a fat arrow function in a d3 selection method that requires you to select this unless you use an alternative way to select that element.

From MDN :

In arrow functions, this retains the value of the enclosing lexical context's this. In global code, it will be set to the global object ... The same applies to arrow functions created inside other functions: their this remains that of the enclosing lexical context.


However, you can certainly keep the arrow function and still reference the element that would be this , as the second argument is the current index, and the third argument is an array of elements in the selection. This answer already speaks to this method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM