React JS - Composing generic form with dynamic childrens

Viewed 3589

I am just a beginner in reactjs. I feel so good about using it, but I have been stuck for a while on a concept that I wanna implement, that would solve me whole lot of other issues.

Concept

  • I want to create a form component that can have dynamic children passed to it. It won't be a specific form component like LoginForm, ContactForm etc. Rather it would just be Form.

Approach 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 calls the validate function that just passes on the args to the Form's validate function. For the Form to know if all it's children's are validated. I pass isValid and targetInputComponent as args to the form.
  • Button Submit onClick calls the submit function likewise and LoginPage (acts as middleware) passes the call to the Form component. Form check it's state for inValid inputs etc.
  • Button Reset onClick call is passed to the Form component likewise. But how do the form handle this reset functionality? Input's value is controlled by LoginPage. Form can't change the input's value.

Aproach 2

What I did was add the input's data and validity to the LoginPage state. Now both Form and Inputs just call the Login Page to update it's state. Form and Inputs components are using this state as 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>
    }
}

Problem

This approach is making the LoginPage Component quite messy. How will the LoginPage component will handle the forms if I have more than 1 form on the page? There will be even more features to LoginPage like Lists, Grid, Modals etc. This LoginPage shouldn't Handle these situations. Form should be responsible for all the inputs, submition, etc functionality. This form component should be generic to all types of forms. I don't want to create feature forms like LoginForm, ContactForm, etc.

The solution to this issue will aid me a lot in whole lot of other components.

2 Answers

There are numerous ways to make ‘generic’ forms. But in my opinion it is best to keep the forms seperatly.

The reason why I say this, is because one way or another, you still have to implement various validation condition for most fields, such as e-mailaddress or what ever you will use.

I think the best approach is to make the components individual. For example: make a TextField component that handles input stuff like validation. Maybe a Button component for submit and callbacks.

So my advise: keep the forms seperatie. No need to overthink and lose useful time in trying to make things ‘pretty’.

Goodluck!

Related