在React子组件上调用方法

时间:2015-11-02 21:56:55

标签: javascript reactjs

我想编写一个Form组件,可以导出一个方法来验证它的子代。不幸的是,表格并没有“看到”其子女的任何方法。

以下是我如何定义Form的潜在子项:

var Input = React.createClass({
  validate: function() {
    ...
  },
});

以下是我定义Form类的方法:

var Form = React.createClass({
  isValid: function() {
    var valid = true;
    this.props.children.forEach(function(component) {
      // --> This iterates over all children that I pass
      if (typeof component.validate === 'function') {
        // --> code never reaches this point
        component.validate();
        valid = valid && component.isValid();
      }
    });
    return valid;
  }
});

我注意到我可以使用refs在子组件上调用方法,但我不能通过props.children调用方法。

这种React行为有原因吗?

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:16)

技术原因是,在您尝试访问子组件时,它们尚未真正存在(在DOM中)。他们尚未安装。它们已作为反应传递给您的<Form>组件作为构造函数或方法。 (因此React.createClass())中的名称类。

正如您所指出的,这可以通过使用refs来规避,但我不会推荐它。在许多情况下,refs往往是那些反应不适合的东西的捷径,因此应该避免。

可能通过设计反应使父母很难/不可能使用儿童的方法。他们不应该这样做。如果孩子对孩子是私人的,孩子的方法应该在孩子身上:他们在孩子内部做一些事情,不应该直接向父母传达。如果是这种情况,那么应该在父母内部进行处理。因为父母至少拥有孩子拥有的所有信息和数据。

现在在你的情况下,我想每个输入(子)组件都有某种特定的验证方法,它检查输入值,并根据结果,做一些错误信息反馈。让我们说一下不正确字段周围的红色轮廓。

在反应方式中,这可以通过以下方式实现:

  • <Form>组件具有状态,其中包含runValidation布尔值。
  • 只要runValidation设置为true,setState( { runValidation: true });内部会自动重新呈现所有孩子。
  • 如果您将runValidation作为支柱包含在所有儿童身上。
  • 然后每个孩子都可以使用render()
  • 之类的内容在if (this.props.runValidation) { this.validate() }函数内部进行检查
  • 将执行子项中的validate()函数
  • 验证功能甚至可以使用孩子的状态(当新道具进入时状态不会改变),并将其用于验证消息(例如,请在密码中添加更复杂的符号) )

现在还没有解决的问题是,您可能希望在所有孩子自己验证后在表单级别进行一些检查:例如:当所有孩子都好的时候,提交表格。

要解决此问题,您可以将refs快捷方式应用于最终检查并提交。并在<Form>函数内的componentDidUpdate()中实施一种方法,检查每个孩子是否正常(例如是否有绿色边框)以及是否单击了提交,然后提交。但作为一般规则,我强烈建议不要使用引用。

对于最终表单验证,更好的方法是:

  • <Form>内添加一个非状态变量,其中包含每个孩子的布尔值。注意,它必须是非状态的,以防止儿童触发新的渲染周期。
  • validateForm函数作为(回调)道具传递给每个孩子。
  • 在每个子项中的validate()内,调用this.props.validateForm(someChildID)更新表单中变量的相应布尔值。
  • 在表单中validateForm函数的末尾,检查所有布尔值是否为真,如果是,请提交表单(或更改表单状态或其他)。

对于在反应(使用通量)中形成验证的更长时间(并且更复杂)的解决方案,您可以检查this article

答案 1 :(得分:1)

我不确定我是否遗漏了某些东西,但是在尝试了什么@wintvelt建议我在React的render方法中调用runValidation方法时遇到问题,因为在我的情况下{{ 1}}通过调用runValidation来改变状态,从而触发渲染方法,这显然是一种不好的做法,因为渲染方法必须是纯粹的,如果我把setState放在runValidation中它不会被第一次调用,因为willReceiveProps条件尚未成立(使用if在父组件中更改此条件,但在setState的第一次调用中它仍然是假)。