ES6 方法未在 create-react-app 中定义

ES6 method is not defined in create-react-app

我很难理解为什么 create-react-app 无法编译,告诉我 error 'updateWord' is not defined no-undef。我是 React with ES6 的新手。通常我会写一个像 const App = React.createClass({ }); 这样的组件,但我决定尝试一些语法糖来代替。

我有父组件 App 和一个子组件 Input:

class App extends Component {
  constructor(props) {
    super(props);
    // all other code omitted...
  }

  handleInput(input) {
    console.log(`handle: ${input}`); 
    updateWord(input);
    // this also causes an error
    // this.updateWord(input);
  }

  updateWord(input) {
    console.log(`update ${input}`);
    // why isn't this defined?
  }

  render() {
    return (
      <div className="App">
        <Input onInput={this.handleInput} />
      </div>
      );
  }
}

class Input extends Component {
  handleInput(e) {
    let input = e.target.value;
    this.props.onInput(input);
  }

  render() {
    return (
      <form>
        <input onChange={this.handleInput.bind(this)} />
      </form>
      );
  }
}

我试过将 updateWord(input) 改为 this.updateWord(input); 但无济于事。我得到:

"App.js:55 Uncaught TypeError: this.updateWord is not a function" 

通常,当我实现与我现在正在做的类似的模式(使用 ES5)时,我没有任何困难。例如:

const App = React.createClass({
  getInitialState: function() {
    // all other code omitted...
  },

  handleInput: function(input) {
    console.log(`handle: ${input}`); 
    this.updateWord(input);
  },

  updateWord: function(input) {
    console.log(`update ${input}`);
    // In theory, this implementation would not cause any errors?
  },

  render: function() {
    return (
      <div className="App">
        <Input onInput={this.handleInput} />
      </div>
      );
  }
}

问题是,当您在 this.handleInput 中执行 this.updateWord(...) 时,this 指的是 Input 组件。让我来说明问题:

当您设置 onInput 处理程序时,如下所示:

onInput={this.handleInput}

此处,由于您的 Input 组件正在调用该函数,因此 this 指的是 Input 组件。这是由于行:

this.props.onInput(input);

Input 组件正在调用 handleInput。这意味着,在您的 handleInput 函数中,this 上下文是 Input。考虑以下行:

this.updateWord(input);

handleInput 函数中。这里调用了 this.updateWord,但是由于 thisInput,它试图从不存在的 Input 调用 updateWord,从而抛出错误。


解决方案是显式绑定 this 上下文 作为 class(App 组件) 而不是 Input 组件,使用 Function.prototype.bind or an arrow function。来自文档:

The bind() method creates a new function that, when called, has its this keyword set to the provided value

您可以这样应用它:

onInput={this.handleInput.bind(this)}

或者更优选在构造函数中:

this.handleInput = this.handleInput.bind(this);

如果选择第二个选项,您可以执行以下操作:

onInput={this.handleInput}

(这更可取,因为 render 方法中的绑定将在每次渲染时创建一个新函数,这不是首选)。

上一行中的 this 上下文是 class。由于您绑定 this,因此 class 将被正确用作函数中的 this 上下文,执行 this.updateWord 将调用该方法在class

一种更好的方法是使用箭头函数而不是常规的 ES6 方法。来自文档:

An arrow function expression has a shorter syntax compared to function expressions and does not bind its own this, arguments, super, or new.target.

我们可以通过将 handleInput 分配给箭头函数而不是常规方法来应用它:

handleInput = (input) => {
    console.log(`handle: ${input}`); 
    this.updateWord(input);
}

这将完全消除 bind 的使用,而是使用箭头函数。由于箭头函数不绑定它们自己的 this,这意味着 this 指的是封闭的上下文。在上面的示例中,未使用方法,因此 this 指的是 class(封闭上下文)。这将正确调用 class 方法 updateWord,因此,如果您走这条路,则无需更改 onInput 事件处理程序。