在React中为类属性使用Arrow函数。不清楚

时间:2018-11-15 09:44:20

标签: reactjs this arrow-functions class-properties

我遇到了箭头函数功能,在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>
   )

}

3 个答案:

答案 0 :(得分:1)

当前ECMAScript不正式支持类中用于早期绑定的箭头功能。

在继承了您的类并且子级想要覆盖父级方法时,将箭头用作类方法will get you in trouble

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

  

在Facebook,我们在成千上万的组件中使用React,但还没有发现建议创建组件继承层次结构的用例。

Dan Abramov在组件方法中也using arrow functions,但是他建议仅在需要早期绑定的情况下才使用它。

  

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

但是,正如Dan所指出的那样,为了安全起见,请在构造函数中坚持早期绑定:

  

如果您要遵守语言标准,请在   构造函数是必经之路。这很乏味,但通常您只想要   为事件处理程序执行此操作,按照惯例,您可以使用   在React中处理*,因此记住它们并不太难。


更新:关于您的情况:

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

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

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

答案 1 :(得分:1)

您需要对功能进行一些如下更改。

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>
   )

}

答案 2 :(得分:0)

我不会使用箭头功能来做到这一点,但是可以。我将解释这两种方法(还有更多方法),第一种是我通常使用的方法。

使用高级函数(或方法)进行绑定

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

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

您可以将其简单地绑定为:

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

它的优点是您不需要在构造函数中绑定到此。

使用箭头功能

代码相似,但是您必须在构造函数中绑定此代码。

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

绑定:

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

在构造函数上绑定此

 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>