4

我遇到了在 React 组件中用作 Class 属性的箭头函数功能。在网上看,我发现它使代码更具可读性,并且由于箭头函数的特性,我们不必在构造函数中绑定handlEvents函数。

即使在为类属性使用箭头函数时,我仍然必须使用 bind 方法,如下面的代码所示。当我删除构造函数中的绑定时,它会在控制台中显示错误,Warning: A component is changing an uncontrolled input of type text to be controlled.并且表单错误也不会显示

class Contact extends Component {
    constructor(props) {
        super(props);

        this.handleBlur = this.handleBlur(this);
    }

    handleBlur = evt => field => {
        this.setState({
        touched: { ...this.state.touched, [field]: true }
    });

   render() {
       return(
          <Form onSubmit={this.handleSubmit}>
            <FormGroup row>
              <Label htmlFor="firstname" md={2}>
                First Name
              </Label>
              <Col md={10}>
                <Input
                  type="text"
                  id="firstname"
                  name="firstname"
                  placeholder="First Name"
                  valid={errors.firstname === ""}
                  invalid={errors.firstname !== ""}
                  value={this.state.firstname}
                  onBlur={event => {
                    this.handleBlur("firstname");
                  }}
                  onChange={this.handleInputChange}
              />
              <FormFeedback>{errors.firstname}</FormFeedback>
            </Col>
          </FormGroup>
       </Form>
   )

}
4

3 回答 3

2

当前的 ECMAScript 不正式支持类中早期绑定的箭头函数。

当您的类被继承并且孩子想要覆盖父方法时,使用箭头函数作为类方法会给您带来麻烦。

但是,我想说在你的 react 组件中使用它们是非常安全的,因为在这里你不会遇到继承问题,因为使用 react 你通常不会进一步从你自己的组件继承(参见Composition vs Inheritance):

在 Facebook,我们在数以千计的组件中使用 React,我们还没有发现任何建议创建组件继承层次结构的用例。

Dan Abramov 也在组件方法中使用箭头函数,但是他建议仅在需要早期绑定时使用它。

虽然它仍然是实验性的,但根据我的经验,它很好地解决了这个问题。它根本不是 React 特定的:我发现它在任何处理异步和回调的类中都很有用,因为绑定问题对所有 JavaScript 都很常见,而不仅仅是 React。我们在整个 Facebook 代码库中启用了这个语法提议,如果它被删除或更改,我们将确保发布一个自动 codemod 以迁移到新语法(或者,最坏的情况,将其转换回构造函数中的绑定调用) .

然而,正如 Dan 指出的那样,为了在安全站点上,坚持在构造函数中进行早期绑定:

如果你想坚持语言标准,在构造函数中手动绑定是要走的路。这很乏味,但通常您只想为事件处理程序执行此操作,并且按照惯例,您在 React 中以 handle* 开头,因此记住绑定它们并不难。


更新:关于您的情况:

在您的情况下,您可以使用 Anshul Bansal 提供的解决方案,在其中将字段名传递给您handleBlur,并在将返回的函数作为事件回调传递时使用闭包中的字段变量。

evt.target或者您可以通过(代码未测试)直接访问字段的输入名称。

handleBlur = evt => {
    const field = evt.target.name;
    this.setState({
    touched: { ...this.state.touched, [field]: true }
});
于 2018-11-15T09:47:12.310 回答
0

您需要稍微更改功能,如下所示。

class Contact extends Component {
    constructor(props) {
        super(props);

        this.handleBlur = this.handleBlur(this);
    }

    handleBlur = field => () => {
        this.setState({
        touched: { ...this.state.touched, [field]: true }
    });

   render() {
       return(
          <Form onSubmit={this.handleSubmit}>
            <FormGroup row>
              <Label htmlFor="firstname" md={2}>
                First Name
              </Label>
              <Col md={10}>
                <Input
                  type="text"
                  id="firstname"
                  name="firstname"
                  placeholder="First Name"
                  valid={errors.firstname === ""}
                  invalid={errors.firstname !== ""}
                  value={this.state.firstname}
                  onBlur={this.handleBlur("firstname")}
                  onChange={this.handleInputChange}
              />
              <FormFeedback>{errors.firstname}</FormFeedback>
            </Col>
          </FormGroup>
       </Form>
   )

}
于 2018-11-15T10:22:23.617 回答
0

我不会用箭头函数来做,但你可以。两种方法我就解释一下(还有几个),第一种是我平时用的。

绑定高阶函数(或方法)

它只是一个返回事件回调的方法,因为 this 是一个已经绑定到 this 的方法。这样,您可以将任何参数传递给作为闭包的方法,并且这些参数将出现在回调中。这就是field论证的情况。请注意,我切换了参数的顺序,字段应该是第一个,因为它首先被调用以返回回调。

  handleBlur(field) {
    return evt => {
      console.log(this.state);
      this.setState({
        touched: { ...this.state.touched,
          [field]: true
        }
      });     
    };
  }

你可以简单地绑定它:

onBlur = {this.handleBlur("firstname")}

这样做的好处是您不需要在构造函数中绑定到 this。

使用箭头函数

代码类似,但您必须在构造函数中绑定到 this。

handleBlurArrow = field => evt => {
      console.log(this.state);
      this.setState({
        touched: { ...this.state.touched,
          [field]: true
        }
      });     
 };

捆绑:

 onBlur = {this.handleBlurArrow("firstnameArrow")}

在构造函数上绑定 this:

 this.handleBlurArrow = this.handleBlurArrow.bind(this);

工作示例

class Contact extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
    this.handleBlurArrow = this.handleBlurArrow.bind(this);
  }
  
  handleBlurArrow = field => evt => {
      console.log(this.state);
      this.setState({
        touched: { ...this.state.touched,
          [field]: true
        }
      });     
 };
  


  handleBlur(field) {
    return evt => {
      console.log(this.state);
      this.setState({
        touched: { ...this.state.touched,
          [field]: true
        }
      });     
    };
  }

  render() {
    return (<div> 
      <input type = "text"   id = "firstname"
        name = "firstname"
        placeholder = "First Name"
      value = {this.state.firstname}
      onBlur = {this.handleBlur("firstname")}
      onChange = {this.handleInputChange}
      /> 
      <input type = "text"   id = "firstnameArrow"
        name = "firstname"
        placeholder = "First Name Arrow"
      value = {this.state.firstname}
      onBlur = {this.handleBlurArrow("firstnameArrow")}
      onChange = {this.handleInputChange}
      /> 
      </div>

    )

  }
}

ReactDOM.render( <Contact /> ,
    document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

于 2018-11-15T10:50:13.850 回答