0
\$\begingroup\$

As an introduction, I would like to have my inputs validated with the built-in validation HTML5 attributes, e.g. use pattern for text input. So this is my sample code that implements that.

Is it considered best practice while handling event, to access event.target, which is the original DOM, and do something with it, rather than dealing with React virtual DOM?

Please let me know if there are more improvements can be made. I'm using React.js 0.14.7. Thanks.

NodeList.prototype.forEach = Array.prototype.forEach;


class InputSet extends React.Component {
    render() {
        return (
            <div>
                <input type="text" defaultValue={this.props.firstName} data-field="firstName" required/>
                <input type="text" defaultValue={this.props.lastName} data-field="lastName" required/>
            </div>
        );
    }
}


class FormWithValidation extends React.Component {
    handleSubmit(event) {
        event.preventDefault();
        console.log(event.target);

        let childNodes = Array.prototype.slice.call(event.target.childNodes);
        childNodes = childNodes.filter((elm) => elm.tagName === 'DIV');
        const values = childNodes.map((div) => {
            const value = {};
            div.childNodes.forEach((input) => {
                const field = input.getAttribute("data-field");
                value[field] = input.value
            })
            return value;
        });

        // Do something with values.
        console.log(values);
    }

    render() {
        const inputSets = [
            {firstName: "Donald", lastName: "Duck"},
            {firstName: "Bill", lastName: "Williams"}
        ]

        return (
            <form action="" onSubmit={this.handleSubmit} >
                {inputSets.map((obj, index) => {
                    return <InputSet {...obj} key={index} />
                })}
                <input type="submit" value="Save"/>
            </form>
        );
  }
}


ReactDOM.render(<FormWithValidation/>, document.getElementById('container'))
\$\endgroup\$
2
\$\begingroup\$

It is fine to read event.target in react. In many cases (e.g. finding out which item was clicked) it's the only way to get the data your code needs.

It is generally considered best practice to not change DOM directly, but let react handle have monopoly on DOM changes -> You're good here, you do not change DOM, you only read from it.

Two things that could be improved:

  • You store the field name in data-field, and later on read it to find out which div is which field. This is not so clean react code.
  • You read the entire form from event.target, filtering out all divs.

It may work, and it is efficient: react is only triggered after submit is clicked. But the code is very dependent on the structure of your form in the real DOM. If there is one div to many in your real DOM, then your code breaks down. And to debug, one also needs to understand the tricky real DOM traversal methods (e.g. that a DOM node is not the same as a DOM element).

I would advise to refactor to a react-only solution, making the following changes:

  • Give your FormWithValidation component state, which stores an array of inputset values (firstname and lastname)
  • Pass down a this.valueUpdate method, which individual fields can invoke to update state. The method would receive an index (of the input set), a fieldname, and a new value.
  • Make a single component for a single input field, which can receive the fieldname as a prop.
  • Give the input field an onBlur handler. Which calls this.props.valueUpdate.

This refactoring has two disadvantages:

  • it is a lot more code for these simple tasks
  • react will do a lot more cycles: every time an input field has changed, react will update state and re-render the form (efficiently and only diffs of course)

The big advantage is that all your code and all your logic lives inside the react structure and lifecycle. Which will make your code easier to maintain.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.