【问题标题】:React, cloneElement - invariant error反应,cloneElement - 不变的错误
【发布时间】:2026-02-09 20:20:04
【问题描述】:

我的团队一直在尝试提前思考使用 React 组件进行表单验证的主题。

我们一直在关注我们看过的指南here,它看起来非常棒且经过深思熟虑。

这里的组件上有一个属性,看起来像这样:

registerInputs: function (children) {
  React.Children.forEach(children, function (child) {
    if (child.props.name) {
      child.props.attachToForm = this.attachToForm;
      child.props.detachFromForm = this.detachFromForm;
    }

    if (child.props.children) {
      this.registerInputs(child.props.children);
    }
  }.bind(this));
},
attachToForm: function (component) {
  this.inputs[component.props.name] = component;
},
detachFromForm: function (component) {
  delete this.inputs[component.props.name];
}

这样做的问题是以这种方式附加道具会给你一个反应警告,它建议使用 cloneElement 代替。虽然它确实有效,但它只是给出了一些我不喜欢看到的控制台警告。

所以以 ES6 的方式,我的团队想出了这个:

registerInputs = children => {
    React.Children.forEach(children, child => {
        if (child.props.name) {
            React.cloneElement(child, {
                attachToForm: this.attachToForm,
                detachFromForm: this.detachFromForm
            })
            //child.props.attachToForm = this.attachToForm;
            //child.props.detachFromForm = this.detachFromForm;
        }
        if (child.props.children) {
            this.registerInputs(child.props.children);
        }
    })
}
attachToForm = component => {
    this.inputs[component.props.name] = component;
    this.model[component.props.name] = component.state.value;
}
detachFromForm = component => {
    delete this.inputs[component.props.name];
    delete this.model[component.props.name];
}

不起作用,我们得到一个不变的错误,说找不到 dom 节点(那个说你要么缺少 <tbody> 等等)。

澄清一下:如果我们注释掉 cloneElement 块,并取消注释子组件上的 prop 显式声明,它可以工作 - 但有警告。

我们尝试了其他一些解决方案,包括发布在here 的类似问题 但这对我们不起作用。我们还尝试了映射,这在 react 文档中似乎很常见,并以这种方式返回带有新道具的新数组,但我们不断收到不变的错误。

为什么在对象点表示法中设置道具有效(尽管建议不要这样做)而克隆元素方法无效?

控制台日志似乎表明,按照我们上面所做的方式克隆孩子并添加道具实际上并没有向道具对象添加任何内容。

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    formsy-react库,来自同一作者,它实现了博客文章中公开的方法的updated version

    traverseChildrenAndRegisterInputs: function(children) {
    
        if (typeof children !== 'object' || children === null) {
            return children;
        }
        return React.Children.map(children, function(child) {
    
            if (typeof child !== 'object' || child === null) {
                return child;
            }
    
            if (child.props && child.props.name) {
    
                return React.cloneElement(child, {
                    _attachToForm: this.attachToForm,
                    _detachFromForm: this.detachFromForm,
                    _validate: this.validate,
                    _isFormDisabled: this.isFormDisabled,
                    _isValidValue: function(component, value) {
                        return this.runValidation(component, value).isValid;
                    }.bind(this)
                }, child.props && child.props.children);
            } else {
                return React.cloneElement(child, {}, this.traverseChildrenAndRegisterInputs(child.props && child.props.children));
            }
    
        }, this);
    
    }
    

    【讨论】:

      最近更新 更多