在 React 子组件上调用方法

Posted

技术标签:

【中文标题】在 React 子组件上调用方法【英文标题】:Call methods on React children components 【发布时间】:2016-02-02 22:24:42 【问题描述】:

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

以下是我如何定义 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 行为是否有原因?

我该如何解决这个问题?

【问题讨论】:

【参考方案1】:

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

正如您所指出的,这可以通过使用 refs 来规避,但我不建议这样做。在许多情况下,refs 往往是一些不适合 react 的东西的快捷方式,因此应该避免。

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

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

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

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

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

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

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

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

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

【讨论】:

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

我不确定我是否遗漏了什么,但是在尝试了@wintvelt 的建议之后,每当我在 React 的渲染方法中调用runValidation 方法时,我都会遇到问题,因为在我的情况下,runValidation 发生了变化通过在其中调用setState 来触发状态,从而触发渲染方法,这显然是一种不好的做法,因为渲染方法必须是纯的,如果我将runValidation 放在willReceiveProps 中,它不会第一次被调用,因为if 条件还不成立(在父组件中使用 setState 更改了此条件,但在第一次调用 willReceiveProps 时仍然为假)。

【讨论】:

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

以上是关于在 React 子组件上调用方法的主要内容,如果未能解决你的问题,请参考以下文章

Vue/React:调用函数传递数据的正确方法?

react 子组件调用父组件方法

react ,父子调用子组件的方法与子组件调用父组件的方法

react中父组件调用子组件方法(onRef)

react 父组件怎么调用子组件的方法

react 下拉框 组件多次被调用