在 React 子组件上调用方法

IT技术 javascript reactjs
2021-04-15 03:57:33

我想编写一个可以导出方法来验证其子项的 Form 组件。不幸的是,一个 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个回答

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

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

React 可能是有意设计的,让父母很难/不可能访问孩子的方法。他们不应该这样做。如果孩子的方法对孩子来说是私有的,那么孩子的方法应该在孩子中:他们在孩子内部做一些不应该直接向上传达给父母的事情。如果是这种情况,那么处理应该在父级内部完成。因为父母至少拥有孩子拥有的所有信息和数据。

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

在react方式中,这可以实现如下:

  • <Form>组分具有的状态,其中包括一个runValidation布尔值。
  • 一旦runValidation设置为 true,在setState( { runValidation: true });react 中会自动重新渲染所有子项。
  • 如果您runValidation将所有孩子作为props包括在内
  • 然后每个孩子都可以render()用类似的东西检查他们的功能if (this.props.runValidation) { this.validate() }
  • 这将validate()在孩子中执行该功能
  • 验证函数甚至可以使用孩子的状态(新props进入时状态不会改变),并将其用于验证消息(例如“请向您的密码添加更复杂的符号”)

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

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

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

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

对于更冗长(且方式更复杂)的react(使用通量)中的表单验证解决方案,您可以查看这篇文章

因为您不希望表单在每个孩子报告“OK”或“not Ok”时完全重新呈现,如果您将其置于表单状态,则会发生这种情况。您只想拥有完整表单的状态,并且只有在所有子项都正常时才更改状态/重新渲染。
2021-06-04 03:57:33
为什么验证变量应该是非状态变量?
2021-06-22 03:57:33

我不确定我是否遗漏了什么,但是在尝试了 @wintvelt 建议的内容之后,每当我在runValidationReact 的渲染方法中调用该方法时,我都会遇到问题,因为在我的情况下runValidation,通过调用setState它来更改状态,从而触发渲染方法显然是一个不好的做法,因为渲染方法必须是纯的,如果我把放进去runValidationwillReceiveProps它不会第一次被调用,因为if条件还不为真(这个条件在父组件中使用setState,但是在willReceiveProps它的第一次调用中它仍然是错误的)。

可能最好就此主题提出另一个问题。但作为一个解释:在我的回答中,父级 (Form) 拥有一个布尔标志 ( runValidation),它决定了子级的validate()方法是否应该运行。孩子内部的这个方法是孩子渲染的一部分,不应该(或需要)改变孩子的状态。validate()方法仅用于确定是否需要更新任何显示的验证消息。
2021-06-01 03:57:33