Ionic React의 형식 및 유효성 검사
게시 됨: 2022-03-10Ionic Framework는 HTML, CSS 및 JavaScript를 사용하여 크로스 플랫폼 모바일 애플리케이션을 구축하기 위한 UI 툴킷입니다. 2020년 초 Ionic 5 릴리스는 React에 대한 공식 지원과 함께 제공되어 React 개발자가 선호하는 도구를 사용하여 모바일 애플리케이션을 쉽게 구축할 수 있습니다. 그러나 양식 작업에 대한 지원은 많지 않으며 React 생태계에서 양식을 빌드하는 데 사용할 수 있는 기존 라이브러리 중 많은 수가 Ionic Framework의 구성 요소와 잘 작동하지 않습니다.
이 튜토리얼에서 Ionic React의 UI 입력 구성 요소를 사용하여 양식을 작성하는 방법을 배웁니다. 또한 양식 입력 변경을 감지하고 유효성 검사 규칙에 응답하는 데 도움이 되는 라이브러리를 사용하는 방법을 배우게 됩니다. 마지막으로 입력의 ARIA 속성에 유용한 텍스트를 추가하여 화면 판독기에서 양식에 액세스할 수 있도록 하는 방법을 배웁니다.
Ionic의 양식 구성 요소
양식은 오늘날 대부분의 웹 및 모바일 애플리케이션에서 중요한 부분입니다. 사용자 등록 및 로그인 양식을 통해 애플리케이션의 제한된 부분에 대한 액세스를 활성화하든 사용자로부터 피드백을 수집하든 상관없이 애플리케이션 수명 주기의 어느 시점에서 양식을 작성해야 합니다.
Ionic은 양식 작업을 위해 미리 빌드된 구성 요소를 제공합니다. 그 중 일부는 IonItem
, IonLabel
, IonInput
, IonCheckbox
및 IonRadio
를 포함합니다. 스타일을 추가하지 않고도 이러한 구성 요소를 결합하여 표준 모양의 양식을 만들 수 있습니다.
예를 들어 다음 코드:
<form className="ion-padding"> <IonItem> <IonLabel position="floating">Username</IonLabel> <IonInput /> </IonItem> <IonItem> <IonLabel position="floating">Password</IonLabel> <IonInput type="password" /> </IonItem> <IonItem lines="none"> <IonLabel>Remember me</IonLabel> <IonCheckbox defaultChecked={true} slot="start" /> </IonItem> <IonButton className="ion-margin-top" type="submit" expand="block"> Login </IonButton> </form>
다음과 같은 로그인 양식을 제공합니다.
기본적으로 Ionic의 양식 구성 요소는 iOS 또는 Android에서 멋지게 보이지만 React로 작업하는 경우 다소 다루기 어려울 수 있습니다. React 생태계에 있는 대부분의 도구와 마찬가지로, 디자인만큼 중요한 기능과 접근성과 관련하여 양식을 구축하는 방법을 결정해야 합니다.
선택할 수 있는 React 양식 도우미가 이미 너무 많지만 대부분은 Ionic의 양식 구성 요소와 작동하지 않습니다. 그 주된 이유는 Ionic에서 필드 값이 변경될 때 발생하는 이벤트가 onIonChange
인 반면 대부분의 기존 양식 라이브러리는 onChange
를 수신하기 때문이라고 생각합니다.
React Hook Form: 작고 빠른 React Forms 라이브러리
고맙게도 그것이 모든 운명과 우울은 아닙니다. 나는 최근에 React 프로젝트에서 양식 작업을 위한 라이브러리인 RHF(React Hook Form)를 접했습니다. 제어되거나 제어되지 않는 구성 요소 및 입력 유효성 검사에 대한 지원을 제공하며 API는 후크 기반이므로 기능 구성 요소에서만 작동합니다.
내 생각에 Ionic React 개발자에게 가장 매력적인 기능은 제어된 구성 요소로 작업하기 위해 제공하는 래퍼 <Controller />
구성 요소입니다. 구성 요소에는 전달하는 구성 요소 인스턴스에 대한 변경 이벤트 이름을 지정하는 데 사용할 수 있는 onChangeName
소품이 있습니다. 다음 섹션에서 이것이 Ionic에서 양식 작업을 정말 쉽게 만드는 방법을 보여 드리겠습니다.
가입 양식 작성
Ionic에서 등록 양식을 작성할 때 RHF가 양식 기능을 어떻게 도와주는지 봅시다. 최신 버전의 Ionic CLI를 실행 중인 경우(확인을 위해 npm i -g @ionic/cli
실행) 다음 명령을 실행하여 React로 새 Ionic 앱을 시작합니다.
ionic start myApp blank --type=react
여기서는 빈 템플릿을 사용했습니다. 특히 구성 요소가 기능 구성 요소로 작성된 경우 React Hook Form 라이브러리를 쉽게 사용하도록 기존 양식을 다시 작성할 수 있어야 합니다.
참고: 이 자습서를 진행하기 전에 Home.tsx에서 ExploreContainer
구성 요소 및 해당 가져오기를 제거해야 합니다.
양식을 시작하려면 프로젝트의 루트 디렉토리에서 다음 명령을 실행하여 React Hook Form 패키지를 설치하십시오.
yarn add react-hook-form
이렇게 하면 프로젝트에서 React Hook Form 라이브러리를 사용할 수 있습니다. 라이브러리를 사용하여 양식 입력 필드를 만들어 보겠습니다. Home.tsx 파일을 열고 그 내용을 다음으로 바꿉니다.
import { IonContent, IonPage, IonText, IonItem, IonLabel, IonInput, IonButton } from "@ionic/react"; import React from "react"; import "./Home.css"; import { Controller, useForm } from 'react-hook-form'; const Home: React.FC = () => { const { control, handleSubmit } = useForm(); const registerUser = (data) => { console.log('creating a new user account with: ', data); } return ( <IonPage> <IonContent className="ion-padding"> <IonText color="muted"> <h2>Create Account</h2> </IonText> <form onSubmit={handleSubmit(registerUser)}> <IonItem> <IonLabel position="floating">Email</IonLabel> <Controller as={<IonInput type="email" />} name="email" control={control} onChangeName="onIonChange" /> </IonItem> <IonButton expand="block" type="submit" className="ion-margin-top"> Register </IonButton> </form> </IonContent> </IonPage> ); }; export default Home;
이렇게 하면 이메일 주소를 수집하기 위한 단일 필드가 있는 양식이 제공됩니다. 중요한 부분을 분해해 보겠습니다(코드 블록에서 강조 표시됨).
먼저 RHF에서 useForm()
후크의 반환 값을 구조화합니다. handleSubmit
은 양식이 유효성 검사를 통과할 때 지정한 핸들러 함수에 입력 값을 전달합니다. control
은 제어된 구성 요소를 RHF에 등록하는 데 사용되는 메서드를 포함하는 개체입니다.
다음으로 표준 양식 항목 블록이 있지만 로그인 양식의 예와 달리 IonInput
구성 요소를 RHF의 <Controller />
구성 요소에 전달하고 <Controller />
의 onChangeName
prop을 Ionic의 변경 이벤트로 설정하여 변경 이벤트를 등록합니다. 이름을 지정하고 useForm()
을 호출하여 컨트롤 개체에 control
소품을 설정합니다.
여기까지는 괜찮지만 거의 동일한 코드를 계속해서 반복하고 있는 자신을 발견할 수 있습니다. 주어진 속성으로 입력 필드를 구축하는 재사용 가능한 Input
구성 요소를 만들 수 있습니다.
Input.tsx 라는 src/components 디렉토리에 파일을 만들고 파일에 다음 코드를 추가합니다.
import React, { FC } from "react"; import { IonItem, IonLabel, IonInput } from "@ionic/react"; import { Controller, Control } from "react-hook-form"; export interface InputProps { name: string; control?: Control; label?: string; component?: JSX.Element; } const Input: FC<InputProps> = ({ name, control, component, label, }) => { return ( <> <IonItem> {label && ( <IonLabel position="floating">{label}</IonLabel> )} <Controller as={component ?? <IonInput />} name={name} control={control} onChangeName="onIonChange" /> </IonItem> </> ); }; export default Input;
이 구성 요소는 name
prop 및 선택적 control
, component
및 label
props를 수신하고 앞에서 소개한 Ionic 양식 구성 요소를 사용하여 입력 필드를 렌더링합니다. 이렇게 하면 양식 입력 필드를 만들 때 작성해야 하는 코드의 양이 줄어듭니다. 이 구성 요소를 사용하여 나머지 양식을 완료할 수 있습니다. 다음 변경 사항으로 Home.tsx 파일을 편집합니다.
import { IonContent, IonPage, IonText, IonInput, IonButton, IonCheckbox, IonItem, IonLabel } from "@ionic/react"; import React from "react"; import "./Home.css"; import { useForm } from "react-hook-form"; import Input, { InputProps } from "../components/Input"; const Home: React.FC = () => { const { control, handleSubmit } = useForm(); const formFields: InputProps[] = [ { name: "email", component: <IonInput type="email" />, label: "Email", }, { name: "fullName", label: "Full Name", }, { name: "password", component: <IonInput type="password" clearOnEdit={false} />, label: "Password", }, ]; const registerUser = (data) => { console.log("creating a new user account with: ", data); }; return ( <IonPage> <IonContent> <div className="ion-padding"> <IonText color="muted"> <h2>Create Account</h2> </IonText> <form onSubmit={handleSubmit(registerUser)}> {formFields.map((field, index) => ( <Input {...field} control={control} key={index} /> ))} <IonItem> <IonLabel>I agree to the terms of service</IonLabel> <IonCheckbox slot="start" /> </IonItem> <IonButton expand="block" type="submit" className="ion-margin-top"> Register </IonButton> </form> </div> </IonContent> </IonPage> ); }; export default Home;
지금까지 설정을 통해 양식의 입력 필드( name
은 유일한 필수 속성)의 배열을 갖게 되었으며 각 필드는 이전의 Input
구성 요소를 사용하여 렌더링되었습니다. 더 나아가 JSON 파일에 필드 데이터를 저장하여 구성 요소 내의 코드를 깨끗한 형태로 유지할 수 있습니다. 이 시점에서 앱( ionic serve
명령으로 https://localhost:8100에서 실행)은 다음과 같아야 합니다.
현장 검증은 어떻습니까?
양식의 입력 필드에 아직 유효성 검사 로직이 없다는 것을 눈치채셨을 것입니다. 실제 사용을 위한 앱이라면 API가 수신 데이터의 유효성을 검사하도록 설정되어 있지 않으면 많은 바람직하지 않은 결과를 초래할 수 있습니다. 그건 그렇고, API는 항상 들어오는 데이터의 유효성을 검사해야 합니다.
RHF는 기본 제공되는 양식 유효성 검사를 위한 HTML 표준과 일치하는 유효성 검사와 함께 제공됩니다. 이것은 필수 필드를 만들거나 최소 및 최대 필드 길이를 설정하는 것과 같은 간단한 유효성 검사에 적합합니다. 복잡한 유효성 검사 논리를 사용하려면 Yup을 사용하는 것이 좋습니다. 모든 개체 스키마 유효성 검사 라이브러리를 사용할 수 있지만 RHF는 기본적으로 Yup을 지원합니다.
다음 명령을 실행하여 라이브러리(및 입력)를 설치합니다.
yarn add yup @types/yup
다음으로 구성 요소의 가져오기에 다음을 추가합니다.
import { object, string } from 'yup'; const Home: React.FC = () => { ... }
그런 다음 구성 요소 상단에 다음 코드를 추가합니다.
const Home: React.FC = () => { const validationSchema = object().shape({ email: string().required().email(), fullName: string().required().min(5).max(32), password: string().required().min(8), }); // ... }
여기에서 객체 스키마를 만들고 yup
을 사용하여 각 속성에 유효성 검사 규칙을 추가했습니다. 개체의 이름은 양식의 입력 태그에 있는 이름과 일치해야 하며 그렇지 않으면 규칙이 트리거되지 않습니다.
마지막으로 다음과 같이 validationSchema
속성을 설정하여 정의한 스키마를 사용하도록 useForm()
후크를 업데이트합니다.
const { control, handleSubmit } = useForm({ validationSchema, });
이제 제출 버튼을 클릭하면 handleSubmit
핸들러가 호출되지 않고 양식 데이터가 제출되지 않습니다. 이것이 정확히 우리가 원했던 것이지만 사용자가 무슨 일이 일어나고 있는지 알 수 있는 방법이 없는 것 같습니다. 필드가 올바르게 채워지지 않은 경우 텍스트 힌트를 표시하여 이 문제를 해결해 보겠습니다.
먼저 Input
구성 요소를 다음과 같이 업데이트합니다.
import React, { FC } from "react"; import { IonItem, IonLabel, IonInput, IonText } from "@ionic/react"; import { Controller, Control, NestDataObject, FieldError } from "react-hook-form"; export interface InputProps { name: string; control?: Control; label?: string; component?: JSX.Element; errors?: NestDataObject<Record<string, any>, FieldError>; } const Input: FC<InputProps> = ({ name, control, component, label, errors, }) => { return ( <> <IonItem> {label && <IonLabel position="floating">{label}</IonLabel>} <Controller as={component ?? <IonInput />} name={name} control={control} onChangeName="onIonChange" /> </IonItem> {errors && errors[name] && ( <IonText color="danger" className="ion-padding-start"> <small>{errors[name].message}</small> </IonText> )} </> ); }; export default Input;
여기에서 RHF에서 오류 개체인 추가 선택적 속성을 수신하도록 구성 요소를 업데이트했으며 오류가 있을 때마다 반환된 입력 필드에 오류 메시지를 표시합니다. 마지막으로, 구조 해제된 객체에 errors 객체를 추가하고 루프의 구성 요소를 업데이트하십시오.
const { control, handleSubmit, errors } = useForm({ validationSchema, });
{formFields.map((field, index) => ( <Input {...field} control={control} key={index} errors={errors} /> ))}
이제 사용자가 올바른 작업을 수행하지 않을 때 양식에서 시각적 신호를 제공합니다. 예를 사용하면 오류 메시지를 변경할 수 있습니다. 사용 중인 유효성 검사 방법에 문자열을 전달하여 이 작업을 수행할 수 있습니다. 예를 들어 이메일의 경우 다음을 수행할 수 있습니다.
{ email: string() .email('Please provide a valid email address') .required('This is a required field'), }
접근성 향상
Ionic의 구성 요소는 일반적으로 해당하는 기본 요소에 대한 래퍼입니다. 즉, 해당 요소의 기존 속성이 전부는 아닐지라도 대부분을 받아들입니다. ARIA 속성을 관련 텍스트로 설정하여 입력 필드를 개선하고 시각 장애가 있는 사용자가 더 쉽게 액세스할 수 있도록 할 수 있습니다.
예제 등록 양식을 계속하려면 Input.tsx 파일을 열고 다음과 같이 변경하십시오.
import React, { FC } from "react"; import { IonItem, IonLabel, IonInput, IonText } from "@ionic/react"; import { Controller, Control, NestDataObject, FieldError } from "react-hook-form"; export interface InputProps { name: string; control?: Control; label?: string; component?: JSX.Element; errors?: NestDataObject<Record<string, any>, FieldError>; } const Input: FC<InputProps> = ({ name, control, component, label, errors, }) => { return ( <> <IonItem> {label && <IonLabel position="floating">{label}</IonLabel>} <Controller as={ component ?? ( <IonInput aria-invalid={errors && errors[name] ? "true" : "false"} aria-describedby={`${name}Error`} /> ) } name={name} control={control} onChangeName="onIonChange" /> </IonItem> {errors && errors[name] && ( <IonText color="danger" className="ion-padding-start"> <small> <span role="alert" id={`${name}Error`}> {errors[name].message} </span> </small> </IonText> )} </> ); }; export default Input;
Controller
에 전달하는 기본 IonInput
구성 요소에는 이제 필드에 오류가 있는지 여부를 나타내는 aria-invalid
속성과 해당 오류 메시지를 가리키는 aria-describedby
descriptedby 속성이 포함됩니다. 오류 메시지는 이제 ARIA 역할이 "오류"로 설정된 span
로 래핑됩니다. 이제 필드에 오류가 있으면 화면 판독기가 해당 필드를 강조 표시하고 오류 메시지를 읽어줍니다.
- 여기에서 GitHub 리포지토리를 찾을 수 있습니다.
결론
축하합니다! Ionic을 사용하여 플랫폼 간 앱을 빌드할 때 양식을 빌드하고 유효성을 검사하는 방법을 배웠습니다. 또한 시각 장애가 있는 사용자가 입력 필드에 액세스할 수 있도록 하는 것이 얼마나 쉬운지 확인했습니다. 바라건대, 이 튜토리얼은 Ionic React 앱에서 양식을 작성할 때 사용할 수 있는 견고한 플랫폼을 제공합니다. 이 튜토리얼에서 살펴보지 않은 다른 구성 요소(예: 선택 및 라디오)가 있지만 공식 문서에서 더 많이 찾아 읽을 수 있습니다.
참고문헌
- Ionic 프레임워크 문서
- 반응 후크 양식
- 그래 문서
- 이메일 주소 확인에 대한 Phil Haack
- MDN 웹 문서의 접근성