React:如何在 AddListener() 中使用 setState?

IT技术 reactjs listener bind typeerror setstate
2021-05-21 11:51:04

我有一个方法可以调用 addListener 来处理直到您单击按钮才存在的数据。但是,当我尝试在状态中设置该数据时,出现以下错误:

类型错误:this.setState 不是函数

我试过像这样绑定我的 dataHandler:

this.dataHandler = this.dataHandler.bind(this)

但它仍然返回此错误。我在这里忘记了什么?

constructor(props){
    super(props)
    this.state = {
        selActive: 4,
        loaded: false,
        mapInfo: ''
    }
    this.onScriptLoad = this.onScriptLoad.bind(this)
    this.dataHandler = this.dataHandler.bind(this)
}

dataHandler = (getJson) => {
    fetch(getJson)
        .then(response => response.json())
        .then(featureCollection => 
            dataLayer = map.data.addGeoJson(featureCollection)
        );
    map.data.addListener('mouseover', function(event) {
        map.data.revertStyle();
        map.data.overrideStyle(event.feature, {fillColor: 'blue'});
        // THIS IS WHERE I ADD MY SETSTATE. 
        // HOWEVER, THIS RETURNS AN ERROR ON HOVER
        this.setState({mapInfo: event.feature.countryNL})
    });
}
3个回答

在 JavaScript 中,this总是指我们正在执行的函数的“所有者”,或者更确切地说,是指函数作为其方法的对象。改用箭头函数。箭头函数没有自己的this/super/arguments绑定。它从其父词法范围继承它们。

map.data.addListener('mouseover', (event) => {
    map.data.revertStyle();
    map.data.overrideStyle(event.feature, {fillColor: 'blue'});
    // THIS IS WHERE I ADD MY SETSTATE. 
    // HOWEVER, THIS RETURNS AN ERROR ON HOVER
    this.setState({mapInfo: event.feature.countryNL})
});

参考:

this在普通函数中,要么引用全局对象,要么引用当前实例(在通过 调用的情况下new)。然而this,箭头函数内部是从外部作用域捕获的。所以this在那个addListener回调里面是指全局对象(window)。要解决此问题,您有以下选择:

  • 使用箭头函数:

    map.data.addListener('mouseover', (event) => {
        map.data.revertStyle();
        map.data.overrideStyle(event.feature, {fillColor: 'blue'});
        // THIS IS WHERE I ADD MY SETSTATE. 
        // HOWEVER, THIS RETURNS AN ERROR ON HOVER
       this.setState({mapInfo: event.feature.countryNL})
    });
    
  • 使用绑定函数

    map.data.addListener('mouseover', function (event) {
        map.data.revertStyle();
        map.data.overrideStyle(event.feature, {fillColor: 'blue'});
        // THIS IS WHERE I ADD MY SETSTATE. 
        // HOWEVER, THIS RETURNS AN ERROR ON HOVER
       this.setState({mapInfo: event.feature.countryNL})
    }.bind(this));
    

首先,我不建议你使用匿名函数来设置事件监听器,因为在这种情况下你将无法removeEventListener或类似的东西(可能,因为不清楚,map这里是什么)。

第二件事是你不应该绑定你的dataHandler,因为它已经是一个箭头函数,所以上下文this内部没有问题dataHandler您应该绑定的是您的手动事件列表器。所以结果代码应该是这样的:

constructor(props){
    super(props)
    this.state = {
        selActive: 4,
        loaded: false,
        mapInfo: ''
    }
    this.onScriptLoad = this.onScriptLoad.bind(this)
    this.dataHandler = this.dataHandler.bind(this)
    this.handleMouseOver = this.handleMouseOver.bind(this)
}

dataHandler = (getJson) => {
    fetch(getJson)
        .then(response => response.json())
        .then(featureCollection => 
            dataLayer = map.data.addGeoJson(featureCollection)
        );
    map.data.addListener('mouseover', this.handleMouseOver);
}

handleMouseOver(event) {
    map.data.revertStyle();
    map.data.overrideStyle(event.feature, {fillColor: 'blue'});
    this.setState({mapInfo: event.feature.countryNL})
}

或者,使用箭头函数,自动绑定:

constructor(props){
    super(props)
    this.state = {
        selActive: 4,
        loaded: false,
        mapInfo: ''
    }
    this.onScriptLoad = this.onScriptLoad.bind(this)
    this.dataHandler = this.dataHandler.bind(this)
}

dataHandler = (getJson) => {
    fetch(getJson)
        .then(response => response.json())
        .then(featureCollection => 
            dataLayer = map.data.addGeoJson(featureCollection)
        );
    map.data.addListener('mouseover', this.handleMouseOver);
}

handleMouseOver = (event) => {
    map.data.revertStyle();
    map.data.overrideStyle(event.feature, {fillColor: 'blue'});
    this.setState({mapInfo: event.feature.countryNL})
}

希望能帮到你!:)