React JS - 用动态子组件组成通用表单

Posted

技术标签:

【中文标题】React JS - 用动态子组件组成通用表单【英文标题】:React JS - Composing generic form with dynamic childrens 【发布时间】:2017-10-31 20:14:37 【问题描述】:

我只是 reactjs 的初学者。我对使用它感觉非常好,但我一直停留在一个我想要实现的概念上,这将解决我很多其他问题。

概念

我想创建一个可以将动态子代传递给它的表单组件。它不会是一个特定的表单组件,如 LoginForm、ContactForm 等。而只是 Form

方法 1

class LoginPage extends Rect.Component 

    constructor(props) 
        super(props)

        this.submit = this.submit.bind(this);
        this.validate = this.validate.bind(this);
        this.reset = this.reset.bind(this);
    

    submit(...args) 
        this.refs.form.submit(args);
    

    validate(...args) 
        this.refs.form.validate(args);
    

    reset(...args) 
        this.refs.form.reset(args);
    

    render() 
        return (
        <LoginPage>
            <Form ref="form" onSubmit=this.submit>
                <Input value="email" pattern="/email_pattern/" onValidate=this.validate />

                <Input value="password" pattern="/password_pattern/" onValidate=this.validate />

                <Button value="submit" action=this.submit />
                <Button value="reset" action=this.reset />
            </Form>
        </LoginPage>
    

Input onChange 调用 validate 函数,该函数只是将 args 传递给 Form 的 validate 函数。让表单知道它的所有孩子是否都经过验证。我将 isValid 和 targetInputComponent 作为 args 传递给表单。 按钮提交 onClick 同样调用提交函数,LoginPage(充当中间件)将调用传递给表单组件。表单检查无效输入等的状态。 Button Reset onClick 调用同样传递给 Form 组件。但是表单如何处理这个重置功能呢? Input 的值由 LoginPage 控制。表单无法更改输入的值。

方法 2

我所做的是将输入的数据和有效性添加到 LoginPage 状态。现在表单和输入都只是调用登录页面来更新它的状态。 Form 和 Inputs 组件使用这个状态作为 prop。

class LoginPage extends React.Component 

    constructor(props) 
        super(props)

        this.state = 
            formSchema: this.initSchema()
        

        this.validateField = this.validateField.bind(this);
        this.submitForm = this.submitForm.bind(this);
    

    initSchema() 
        const formSchema = 
            email: 
                isValid: false,
                value: ''
            ,
            password: 
                isValid: false,
                value: ''
            ,
            password2: 
                isValid: false,
                value: ''
            
        

        return formSchema;
    

    validateField(dataObj, targetComponent) 

        const formSchema = Object.assign(this.state.formSchema, dataObj);

        this.setState( formSchema )
    

    submitForm(isSuccess) 
        console.log(isSuccess);
        console.log('Form Submit: ', this.state.formSchema);

        throw new Error('Submition Error');
    

    reset() 
        // Loop through each object in formSchema and set it's value to empty, inputs will validate themselves automatically.
    

    render() 
        return <div>
            <Form ref="formLogin" className="auth-form" onSubmit=this.submitForm formSchema=this.state.formSchema>
                <h1>
                    Switch Accounts
                </h1>
                <Input type="email" name="email" onValidate=this.validateField value=this.state.formSchema.email.value
                isValid=this.state.formSchema.email.isValid/>

                <Input type="password" name="password" onValidate=this.validateField value=this.state.formSchema.password.value
                isValid=this.state.formSchema.password.isValid/>

                <Button value="Submit" type="submit"  />
            </Form>
        </div>
    

问题

这种方法使 LoginPage 组件变得非常混乱。如果页面上有超过 1 个表单,LoginPage 组件将如何处理这些表单? LoginPage 将有更多功能,如列表、网格、模态等等。这个 LoginPage 不应该处理这些情况。 Form 应该负责所有的输入、提交等功能。这个表单组件应该对所有类型的表单都是通用的。我不想创建像 LoginForm、ContactForm 等功能表单。

这个问题的解决方案将在很多其他组件中帮助我很多。

【问题讨论】:

【参考方案1】:

您的方法 2 是处理此问题的标准方法。

为什么不创建一个单独的&lt;LoginForm&gt;?这样做可以将字段和验证从页面上的其他不相关功能中抽象出来。

如果以后您需要&lt;ContactForm&gt; 或任何其他类型的表单,它将具有不同的字段和不同的验证逻辑,这意味着您无论如何都需要构建它。

不用像redux 这样的东西,你就在正确的轨道上。

【讨论】:

感谢兄弟的澄清。我现在正在继续使用第二种方法。这感觉更易于管理。附:单独表单的问题是我还将创建一个动态列表组件,它可以将表单作为 listItem。而且这些表单将具有动态字段。我不会知道的。所以不能创建单独的表单。 React 只是一个非常轻量级的视图层,组件状态作为 props 向下级联并作为回调备份。有setState 但不幸的是,除了简单的内部组件状态之外,它的可扩展性并不高。您所描述的要求使用全局状态存储。正如我提到的,查看 redux,或者更直观的 mobX【参考方案2】:

有很多方法可以制作“通用”表单。但在我看来,最好将表格分开保存。

之所以这么说,是因为不管怎样,你仍然需要为大多数字段实现各种验证条件,例如电子邮件地址或你将使用的任何内容。

我认为最好的方法是使组件独立。例如:制作一个 TextField 组件来处理诸如验证之类的输入内容。也许是一个用于提交和回调的 Button 组件。

所以我的建议是:保持表格分开。无需过度思考并浪费宝贵的时间来尝试让事物变得“漂亮”。

祝你好运!

【讨论】:

以上是关于React JS - 用动态子组件组成通用表单的主要内容,如果未能解决你的问题,请参考以下文章

在js代码中怎样用react 加载组件

Vue通用组件的封装

子组件的下一个js父路由组件

ReactJS:将 html 文件转换为 React 组件

React js 做通用头部

3YAdmin-专注通用权限控制与表单的后台管理系统模板