2

Khi chúng ta nói về đầu vào của người dùng trong một ứng dụng web, chúng ta thường nghĩ đến các hình thức HTML đầu tiên. Các hình thức web đã có sẵn kể từ phiên bản đầu tiên của HTML. Rõ ràng, tính năng này đã được giới thiệu vào năm 1991 và được chuẩn hóa vào năm 1995 với tên RFC 1866 . Chúng tôi sử dụng chúng ở mọi nơi, với hầu hết mọi thư viện và khung. Nhưng còn React thì sao? Facebook cung cấp đầu vào hạn chế về cách xử lý biểu mẫu. Chủ yếu là về việc đăng ký biểu mẫu và kiểm soát cho các sự kiện tương tác và chuyển trạng thái với thuộc tính "giá trị". Vì vậy, xác nhận mẫu và logic trình là tùy thuộc vào bạn. UI Decent ngụ ý rằng bạn bao gồm logic như "xác thực" / "khi xác thực trường nhập, thông báo lỗi nội tuyến, các yếu tố chuyển đổi tùy thuộc vào tính hợp lệ, trạng thái" nguyên sơ "," gửi ", v.v. Chúng ta có thể không trừu tượng logic này và chỉ cần cắm nó trong các hình thức của chúng tôi? Chúng tôi chắc chắn có thể. Câu hỏi duy nhất là cách tiếp cận và giải pháp để chọn.

Hình thành trong DevKit

Nếu bạn đi với một DevKit như ReactBootstrap hoặc AntDesign, bạn có thể đã hài lòng với các biểu mẫu. Cả hai đều cung cấp các thành phần để xây dựng một hình thức đáp ứng các yêu cầu đa dạng. Ví dụ: trong AntDesign, chúng tôi xác định một biểu mẫu với  phần tử Biểu mẫu và trường biểu mẫu với FormItem , đây là trình bao bọc cho mọi điều khiển đầu vào ngoài tập hợp. Bạn có thể đặt quy tắc xác thực trên FormItem như:

  <FormItem>
     {getFieldDecorator('select', {
       rules: [
         { required: true, message: 'Please select your country!' },
       ],
     })(
       <Select placeholder="Please select a country">
         <Option value="china">China</Option>
         <Option value="use">U.S.A</Option>
       </Select>
     )}
   </FormItem>

Sau đó, ví dụ, trong trình xử lý biểu mẫu, bạn có thể chạy this.props.form.validateFields() để áp dụng xác nhận. Có vẻ như mọi thứ được chăm sóc. Tuy nhiên, giải pháp là cụ thể cho khuôn khổ. Nếu bạn không làm việc với DevKit, bạn không thể hưởng lợi từ các tính năng của nó.

Hình thức xây dựng dựa trên lược đồ

Ngoài ra, chúng ta có thể đi với một thành phần độc lập xây dựng các biểu mẫu cho chúng ta dựa trên các thông số JSON được cung cấp. Ví dụ: chúng ta có thể nhập  thành phần Winterfell và xây dựng một biểu mẫu đơn giản như sau:

<Winterfell schema={loginSchema} ></Winterfell>

Tuy nhiên, lược đồ có thể khá phức tạp . Bên cạnh đó, chúng tôi liên kết bản thân với một cú pháp tùy chỉnh. Một giải pháp khác, dạng  phản ứng-jsonschema , trông tương tự nhưng dựa vào  lược đồ JSON . Lược đồ JSON là một từ vựng bất khả tri của dự án được thiết kế để chú thích và xác thực các tài liệu JSON. Tuy nhiên, nó liên kết chúng ta với các tính năng duy nhất được triển khai trong trình xây dựng và được xác định trong lược đồ.

Formsy

Tôi muốn một trình bao bọc cho biểu mẫu HTML tùy ý của mình, nó sẽ quan tâm đến logic xác thực. Ở đây, một trong những giải pháp phổ biến nhất là  Formsy . Nó trông như thế nào? Chúng tôi tạo thành phần của riêng mình cho trường biểu mẫu và bọc nó bằng HOC ,  withFormsy:

import { withFormsy } from "formsy-react";
import React from "react";

class MyInput extends React.Component {

  changeValue = ( event ) => {
    this.props.setValue( event.currentTarget.value );
  }

  render() {
    return (
      <div>
        <input
          onChange={ this.changeValue }
          type="text"
          value={ this.props.getValue() || "" }
        />
        <span>{ this.props.getErrorMessage() }</span>
      </div>
    );
  }
}

export default withFormsy( MyInput );

Như bạn có thể thấy, thành phần nhận   getErrorMessage() chức năng trong các đạo cụ, mà chúng ta có thể sử dụng để nhắn tin lỗi nội tuyến.

Vì vậy, chúng tôi đã thực hiện một thành phần trường. Hãy đặt nó dưới dạng:

import Formsy from "formsy-react";
import React from "react";
import MyInput from "./MyInput";

export default class App extends React.Component {

  onValid = () => {
    this.setState({ valid: true });
  }

  onInvalid = () => {
    this.setState({ valid: false });
  }

  submit( model ) {
    //...
  }

  render() {
    return (
      <Formsy onValidSubmit={this.submit} onValid={this.onValid} onInvalid={this.onInvalid}>
        <MyInput
          name="email"
          validations="isEmail"
          validationError="This is not a valid email"
          required
        ></MyInput>
        <button type="submit" disabled={ !this.state.valid }>Submit</button>
      </Formsy>
    );
  }
}

Chúng tôi chỉ định tất cả các trình xác nhận trường bắt buộc với thuộc  validations tính (xem  danh sách các trình xác nhận có sẵn ). Với  validationError,  chúng tôi đặt thông báo xác thực mong muốn và nhận từ trạng thái hiệu lực của biểu mẫu trong  onValid và  onInvalid trình xử lý.

Điều đó có vẻ đơn giản, sạch sẽ và linh hoạt. Nhưng tôi tự hỏi tại sao chúng ta không dựa vào xác thực mẫu có sẵn trong HTML5 , thay vì đi với vô số triển khai tùy chỉnh.

Xác thực mẫu HTML5

Công nghệ nổi lên cách đây khá lâu. Việc triển khai đầu tiên đã đi cùng với Opera 9.5 vào năm 2008. Ngày nay, nó có sẵn trong tất cả các trình duyệt hiện đại. Xác thực mẫu (Dữ liệu) giới thiệu các thuộc tính HTML và loại đầu vào bổ sung, có thể được sử dụng để đặt quy tắc xác thực mẫu. Việc xác thực cũng có thể được kiểm soát và tùy chỉnh từ JavaScript bằng cách sử  dụng API chuyên dụng .

Hãy xem xét đoạn mã sau:

<form>
  <label for="answer">What do you know, Jon Snow?</label>
  <input id="answer" name="answer" required>
  <button>Ask</button>
</form>

Đó là một hình thức đơn giản, ngoại trừ một điều - yếu tố đầu vào có một  required thuộc tính. Vì vậy, nếu chúng tôi nhấn nút gửi ngay lập tức, biểu mẫu sẽ không được gửi đến máy chủ. Thay vào đó, chúng ta sẽ thấy một chú giải công cụ bên cạnh đầu vào nói rằng giá trị không tuân theo ràng buộc đã cho (nghĩa là trường không được để trống).


Bây giờ chúng tôi đặt đầu vào một ràng buộc bổ sung:

<form>
  <label for="answer">What do you know, Jon Snow?</label>
  <input id="answer" name="answer" required pattern="nothing|nix">
  <button>Ask</button>
</form>

Vì vậy, giá trị không chỉ là bắt buộc, mà phải tuân theo biểu thức chính quy được cung cấp với thuộc tính pattern.

Thông báo lỗi không phải là thông tin, mặc dù vậy? Chúng tôi có thể tùy chỉnh nó (ví dụ: để giải thích chính xác những gì chúng tôi mong đợi từ người dùng) hoặc chỉ cần dịch:

<form>
  <label for="answer">What do you know, Jon Snow?</label>
  <input id="answer" name="answer" required pattern="nothing|nix">
  <button>Ask</button>
</form>
const answer = document.querySelector( "[name=answer]" );
answer.addEventListener( "input", ( event ) => {
  if ( answer.validity.patternMismatch ) {
    answer.setCustomValidity("Oh, it's not a right answer!");
  } else {
    answer.setCustomValidity( "" );
  }
});

Về cơ bản, trên một sự kiện đầu vào, nó kiểm tra trạng thái của thuộc  patternMismatch tính của trạng thái hợp lệ đầu vào. Bất cứ khi nào giá trị thực không khớp với mẫu chúng tôi xác định thông báo lỗi. Nếu chúng ta có bất kỳ ràng buộc nào khác  trên điều khiển, chúng ta cũng có thể bao quát chúng trong trình xử lý sự kiện.

Không hài lòng với chú giải công cụ? Vâng, chúng không giống nhau trong các trình duyệt khác nhau. Hãy thêm đoạn mã sau:

<form novalidate>
  <label for="answer">What do you know, Jon Snow?</label>
  <input id="answer" name="answer" required pattern="nothing|nix">
  <div data-bind="message"></div>
  <button>Ask</button>
</form>
const answer = document.querySelector( "[name=answer]" ),
      answerError = document.querySelector( "[name=answer] + [data-bind=message]" );

answer.addEventListener( "input", ( event ) => {
  answerError.innerHTML = answer.validationMessage;
});

Ngay cả với chỉ giới thiệu siêu ngắn gọn này, bạn có thể thấy sức mạnh và tính linh hoạt của công nghệ. Xác nhận mẫu bản địa là khá tuyệt vời. Vậy tại sao chúng ta dựa vào vô số thư viện tùy chỉnh? Tại sao không đi với xác nhận tích hợp?

React Đáp ứng API xác thực mẫu

mẫu React -html5 kết nối React (và, tùy chọn, Redux) với API xác thực mẫu HTML5. Nó hiển thị các thành phần Form và  InputGroup (tương tự như đầu vào tùy chỉnh của Formsy hoặc  FormItem trong AntDesign). Vì vậy,  Form xác định hình thức và phạm vi của nó và  xác định phạm vi của trường, có thể có một hoặc nhiều đầu vào. Chúng tôi chỉ đơn giản bọc một nội dung biểu mẫu tùy ý (chỉ các thành phần HTML hoặc React đơn giản) với các thành phần này. Trên các sự kiện của người dùng, chúng tôi có thể yêu cầu xác thực mẫu và nhận các trạng thái cập nhật của các  thành phần  và các thành phần, theo đó, đến hiệu lực đầu vào cơ bản. InputGroupFormInputGroup 

Vâng, chúng ta hãy xem nó trong thực tế. Đầu tiên, chúng tôi xác định phạm vi biểu mẫu:

import React from "react";
import { render } from "react-dom";
import { Form, InputGroup } from "Form";

const MyForm = props => (
  <Form>
  {({ error, valid, pristine, submitting, form }) => (
      <>
      Form content
      <button disabled={ ( pristine || submitting ) } type="submit">Submit</button>
      </>
    )}
  </Form>
);

render( <MyForm ></MyForm>, document.getElementById( "app" ) );

Phạm vi nhận đối tượng trạng thái với các thuộc tính:

  • lỗi - thông báo lỗi hình thức (thường là thông báo xác thực máy chủ). Chúng ta có thể thiết lập nó với  form.setError().
  • hợp lệ - boolean cho biết nếu tất cả các đầu vào cơ bản tuân thủ các ràng buộc đã chỉ định.
  • nguyên sơ - boolean cho biết nếu người dùng chưa tương tác với biểu mẫu.
  • gửi - boolean cho biết biểu mẫu đang được xử lý (chuyển sang true khi nhấn nút gửi và trở về false ngay khi onSubmit trình xử lý không đồng bộ do người dùng xác định  giải quyết).
  • biểu mẫu - ví dụ của thành phần Biểu mẫu để truy cập API.

Ở đây chúng tôi sử dụng chỉ  pristine submitting thuộc tính để chuyển nút gửi sang trạng thái bị vô hiệu hóa.

Để đăng ký đầu vào để xác thực trong khi đóng góp nội dung biểu mẫu, chúng tôi bọc chúng bằng InputGroup

  <InputGroup validate={[ "email" ]} }}>
  {({ error, valid }) => (
          <div>
            <label htmlFor="emailInput">Email address</label>
            <input
              type="email"
              required
              name="email"
              id="emailInput" />
            { error && (<div className="invalid-feedback">{error}</div>)  }
          </div>
  )}
  </InputGroup>

Với validate prop, chúng tôi chỉ định những đầu vào của nhóm sẽ được đăng ký. [ "email" ] có nghĩa là chúng tôi có đầu vào duy nhất, với tên "email" được áp dụng cho nó.

Trong phạm vi, chúng tôi nhận được đối tượng trạng thái với các thuộc tính sau:

  • lỗi - một mảng các thông báo lỗi cho tất cả các đầu vào đã đăng ký.
  • lỗi - thông báo lỗi phát ra cuối cùng.
  • hợp lệ - boolean cho biết nếu tất cả các đầu vào cơ bản tuân thủ các ràng buộc đã chỉ định.
  • inputgroup - ví dụ của thành phần để truy cập API.

Sau khi kết xuất, chúng tôi nhận được một biểu mẫu với một trường email. Nếu giá trị trống hoặc chứa địa chỉ email không hợp lệ khi gửi, nó sẽ hiển thị thông báo xác thực tương ứng bên cạnh đầu vào.

Hãy nhớ rằng chúng tôi đã vật lộn với việc tùy chỉnh các thông báo lỗi trong khi sử dụng API xác thực mẫu gốc? Nó dễ dàng hơn nhiều với  InputGroup:

<InputGroup
    validate={[ "email" ]}
    translate={{
      email: {
        valueMissing: "C'mon! We need some value",
        typeMismatch: "Hey! We expect an email address here"
      }
    }}>
...

Chúng tôi có thể chỉ định bản đồ cho mỗi đầu vào, trong đó các khóa là thuộc tính hợp lệ và giá trị là thông điệp tùy chỉnh.

Vâng, việc tùy chỉnh tin nhắn rất dễ dàng. Điều gì về xác nhận tùy chỉnh? Chúng ta có thể làm điều đó thông qua  validate prop:

<InputGroup validate={{
    "email": ( input ) => {
      if ( !EMAIL_WHITELIST.includes( input.current.value ) ) {
        input.setCustomValidity( "Only whitelisted email allowed" );
        return false;
      }
      return true;
    }
  }}>
...

Trong trường hợp này, thay vì một mảng các tên đầu vào, chúng tôi cung cấp một bản đồ, trong đó các khóa là tên đầu vào và các giá trị là các trình xử lý xác thực. Trình xử lý kiểm tra giá trị đầu vào (có thể được thực hiện không đồng bộ) và trả về trạng thái hợp lệ dưới dạng boolean. Với  input.setCustomValidity,  chúng tôi chỉ định một thông báo xác nhận trường hợp cụ thể.

Xác nhận khi nộp không phải luôn luôn là những gì chúng ta muốn. Hãy thực hiện xác nhận "nhanh chóng". Đầu tiên, chúng tôi xác định một trình xử lý sự kiện cho sự kiện đầu vào:

const onInput = ( e, inputGroup ) => {
  inputGroup.checkValidityAndUpdate();
};

Trên thực tế, chúng tôi chỉ làm cho nhóm đầu vào xác thực lại mỗi lần người dùng nhập vào đầu vào. Chúng tôi đăng ký kiểm soát như sau:

<input
  type="email"
  required
  name="email"
  onInput={( e ) => onInput( e, inputGroup, form ) }
  id="emailInput" />

Từ giờ trở đi, ngay khi chúng tôi thay đổi giá trị đầu vào, nó sẽ được xác thực và nếu nó không hợp lệ, chúng tôi sẽ ngay lập tức nhận được thông báo lỗi.

Bạn có thể tìm thấy mã nguồn của bản demo với các ví dụ ở trên.

Nhân tiện, bạn có thích kết nối cây trạng thái có nguồn gốc thành phần với một cửa hàng Redux không? Chúng tôi cũng có thể làm điều đó.

Gói trưng bày bộ giảm tốc html5form có chứa cây trạng thái của tất cả các mẫu đã đăng ký. Chúng tôi có thể kết nối nó với cửa hàng như thế này:

import React from "react";
import { render } from "react-dom";
import { createStore, combineReducers } from "redux";
import { Provider } from "react-redux";

import { App } from "./Containers/App.jsx";
import { html5form } from "react-html5-form";

const appReducer = combineReducers({
  html5form
});

// Store creation
const store = createStore( appReducer );

render( <Provider store={store}>
  <App ></App>
 </Provider>, document.getElementById( "app" ) );

Bây giờ, khi chúng tôi chạy ứng dụng, chúng tôi có thể tìm thấy tất cả các trạng thái liên quan đến hình thức trong cửa hàng.

Đây là mã nguồn của một bản demo chuyên dụng.

Tóm tắt

React không có logic xác thực mẫu tích hợp. Tuy nhiên, chúng tôi có thể sử dụng các giải pháp của bên thứ ba. Vì vậy, nó có thể là một DevKit, nó có thể là một trình xây dựng biểu mẫu, nó có thể là một logic xác thực biểu mẫu trộn thành phần HOC hoặc trình bao bọc thành nội dung biểu mẫu tùy ý. Cách tiếp cận cá nhân của tôi là một thành phần trình bao bọc dựa trên API xác thực mẫu có sẵn trong HTML và hiển thị trạng thái hợp lệ trong phạm vi của biểu mẫu và trường biểu mẫu.

|