부드러운 어셈블리 생성하기

재사용 가능한 구성 요소를 만드는 것은 매우 어렵다.API를 이해하는 것은 고통스러운 일이다. 특성을 결정하는 것은 쉽지 않고, 코드만 작성해도 겁이 많은 사람에게 적합하지 않다.
이 블로그는 폼 필드를 쉽게 조합할 수 있도록 우리가 다시 사용할 수 있는 입력 그룹을 만드는 방법을 알려줄 것이다.나는 입력 그룹이 무엇인지 설명하고, 우리는 그것이 무엇을 하기를 원하며, 점차적으로 그것을 실현할 것이다.우리가 완성한 후에, 당신은 자신의 구성 요소를 만들 수 있을 뿐만 아니라, 구성 요소를 작성할 때 더욱 안전하기를 바랍니다.
우리가 만들고 있는 구성 요소는 단지 하나의 예일 뿐입니다.응용 프로그램에서 이 특정한 구성 요소를 사용할 필요가 없을 수도 있지만, 장래에는 그 중의 일부 기술을 사용할 것이다.

그러면 입력 그룹은 무엇입니까?


교과서 정의를 어디서든 찾을 수 있을 것 같지는 않지만, 입력 그룹은 특정한 형식의 폼 입력을 표시하고, 관련 탭을 만들고, 오류 메시지를 표시하며, 사용자가 고려할 필요가 없는 상황에서 접근성 문제를 최대한 많이 처리하는 구성 요소이다.기본적으로 폼 입력에 필요한 모든 것은 폼 자체를 제외하고는 없다.

An input group is a component
Kristofer Selbekk


이것이 바로 우리가 오늘 창조해야 할 것이다. 한 걸음 한 걸음.우리 시작합시다!

단계 1: 양식 입력 표시


먼저, 우리는 InputGroup라는 구성 요소를 만들었는데, 이것은 우리가 그에게 전달한 모든 하위 대상을 나타낼 수 있다.
function InputGroup(props) {
  return (
    <div>{props.children}</div>
  );
}
이렇게 하면 모든 형식의 입력을 어셈블리에 전달할 수 있습니다.
<InputGroup>
  <input />
</InputGroup>
그래, 어렵지 않지?아직도 나랑 있어?

2단계: 관련 태그 만들기!


우리는 탭 텍스트를 구성 요소에 전달할 수 있기를 희망합니다.label 아이템을 만듭니다.
function InputGroup(props) {
  return (
    <div>
      <label>{props.label}</label>
      {props.children}
    </div>
  );
}
현재, 우리는 라벨이 어떤 방식으로 입력에 추가되는지 확보해야 한다.이를 위해 htmlFor 속성을 사용합니다.우리는 ID를 도구로 받아들인 다음 태그에 적용합니다.
function InputGroup(props) {
  return (
    <div>
      <label htmlFor={props.id}>{props.label}</label>
      {props.children}
    </div>
  );
}
그러나 이것은 좀 짜증난다. 우리는 ID를 우리에게 동시에 전달해야 한다. InputGroup 와 입력이 필요하다.입력에 자동으로 적용합니다.
function InputGroup(props) {
  return (
    <div>
      <label htmlFor={props.id}>
        {props.label}
      </label>
      {React.Children.map(
        props.children, 
        child => React.cloneElement(child, { id: props.id })
      )}
    </div>
  );
}
뭐, React.Children?React.cloneElement ? 이러한 API는 거의 사용되지 않지만 매우 강력합니다.기본적으로 다음과 같다. 이 구성 요소에 전달된 모든 아이들에게 던전을 만들고 추가 id 도구를 추가한다.

React.Children.map lets us map over children like they were an array. See the docs for more details.

React.cloneElement creates a copy of a React element, and lets us override any props passed in with our own version. See the docs for more details.


이렇게 하면 한 번에 ID를 입력하고 양식 태그에 액세스할 수 있는 태그를 설정할 수 있습니다.
<InputGroup id="first-name" label="First name">
  <input />
</InputGroup>

이점: ID 생략


아마도, 당신은 ID에 진정으로 관심이 없을 것입니다. 사실, 우리는 탭과 입력 작업 방식의 세부 사항을 위한 ID가 필요합니다.만약 우리가 그것을 완전히 전달하지 않을 수 있다면, 그것은 매우 좋지 않겠는가?
사실이 증명하듯이 이것은 매우 가능성이 있다.우리는 임의 문자열 생성기를 사용하여 ID를 만들 수 있으며, ID가 제공되지 않으면 ID에 사용할 수 있습니다.
import uuid from 'uuid/v4';

function InputGroup(props) {
  const id = React.useMemo(() => props.id || 'input-'+ uuid(), [props.id])
  return (
    <div>
      <label htmlFor={id}>
        {props.label}
      </label>
      {React.Children.map(
        props.children, 
        child => React.cloneElement(child, { id })
      )}
    </div>
  );
}
여기서, 우리는 React.useMemo 갈고리를 사용하여 렌더링할 때마다 새 ID를 만들지 않습니다.종속 항목 배열props.id을 전달하여 ID 속성이 특정 이유로 변경된 경우에만 ID를 다시 만들 수 있도록 합니다.
또한 어떤 이유로 필요할 경우 소비자가 자신의 ID를 설정할 수 있도록 허용합니다.이것은 어셈블리 API 설계의 중요한 원칙입니다.

Allow the consumer to override any auto-generated values!


단계 3: 오류 처리 추가


대다수의 표는 모두 어떤 검증을 실현한다.좋은 검증 라이브러리가 많습니다(저는 심지어 제 - calidation!),독자에게 남겨진 선택.InputGroup 구성 요소에 검증 오류를 표시하는 방법을 추가합니다.
우리는 먼저 error 도구를 추가하여 children 아래에 나타낸다.
function InputGroup(props) {
  const id = React.useMemo(() => props.id || 'input-'+ uuid(), [props.id])
  return (
    <div>
      <label htmlFor={id}>
        {props.label}
      </label>
      {React.Children.map(
        props.children, 
        child => React.cloneElement(child, { id })
      )}
      {props.error && (
        <div>{props.error}</div>
      )}
    </div>
  );
}
이것은 매우 직접적이지만, 우리 게임을 좀 높여 봅시다.화면 판독기와 기타 보조 기술을 돕기 위해서, 입력 필드를 무효로 표시해야 합니다.양식 입력aria-invalid 도구를 설정하여 다음을 수행할 수 있습니다.
function InputGroup(props) {
  const id = React.useMemo(() => props.id || 'input-'+ uuid(), [props.id])
  const isInvalid = props['aria-invalid'] || String(!!props.error);
  return (
    <div>
      <label htmlFor={id}>
        {props.label}
      </label>
      {React.Children.map(
        props.children, 
        child => React.cloneElement(child, { id, 'aria-invalid': isInvalid })
      )}
      {props.error && (
        <div>{props.error}</div>
      )}
    </div>
  );
}
여기서 폼에 입력한 aria-invalid 속성을'true '로 설정하고, 비falsy error 속성을 전달할 경우, 예를 들어 오류가 비어 있거나 정의되지 않으면'false' 로 설정합니다.이 도구를 DOM이 원하는 문자열로 강제로 변환하고 있음을 주의하십시오.
마지막으로 우리는 소비자가 자신의 전달aria-invalid을 통해 이 값을 덮어쓰도록 한다.

4단계: 유연성🧘‍♂️


지금까지 우리는 매우 신뢰할 수 있는 입력 그룹 구성 요소를 만들었다.이것은 접근 가능한 문제를 고려하여 입력 탭과 오류를 표시하고 우리가 원하는 입력을 전달할 수 있도록 합니다.하지만 아직 해야 할 일이 있어요.
우리는 사람들이 우리의 구성 요소를 어떻게 사용할지 모르기 때문에, 우리는 사람들이 뭔가를 덮어쓰기를 원할 수도 있다.경우에 따라 labelerror 요소를 닫거나 약간 다른 방식으로 렌더링해야 할 수도 있습니다.우리가 뭔가 할 수 있을 것 같아!
function InputGroup(props) {
  const id = React.useMemo(() => props.id || 'input-'+ uuid(), [props.id])
  const isInvalid = props['aria-invalid'] || String(!!props.error);

  const label = typeof props.label === 'string' ? 
    <label htmlFor={id}>{props.label}</label> :
    React.cloneElement(props.label, { htmlFor: id });

  const error = typeof props.error === 'string' ?
    <div>{props.error}</div> :
    props.error;

  return (
    <div>
      {label}
      {React.Children.map(
        props.children, 
        child => React.cloneElement(child, { id, 'aria-invalid': isInvalid })
      )}
      {props.error && error}
    </div>
  );
}
위에서 설명한 API는 태그와 오류 도구에 문자열 또는 일부 JSX를 전달할 수 있도록 합니다.문자열 값을 전달하면 기본 UI가 표시되지만 일부 JSX를 전달하면 사용자가 문자열 값을 결정합니다.사용법은 다음과 같습니다.
<InputGroup
  label={<MyCustomLabelComponent>First name</MyCustomLabelComponent>}
  error="some error occurred"
>
  <input />
</InputGroup>
이러한 사용자 정의를 사용하면 대부분의 사용 환경에서 구성 요소를 유연하게 사용할 수 있으며 예측 가능한 API를 작게 유지할 수 있습니다.

5단계: 유연성 향상


이 구성 요소는 마지막 가설이 있는데, 나는 그것을 없애고 싶다.이 가설은 우리가 단지 한 아이에게만 전입할 것이고, 이 아이는 표 입력이다.몇 개의 입력을 원하거나 주변에 텍스트를 입력하거나 사용자 정의 UI를 보여 주어야 할 수도 있습니다.우리가 이 문제를 해결합시다.
function InputGroup(props) {
  const id = React.useMemo(() => props.id || 'input-'+ uuid(), [props.id])
  const isInvalid = props['aria-invalid'] || String(!!props.error);

  const label = typeof props.label === 'string' ? 
    <label htmlFor={id}>{props.label}</label> :
    React.cloneElement(props.label, { htmlFor: id });

  const error = typeof props.error === 'string' ?
    <div>{props.error}</div> :
    props.error;

  return (
    <div>
      {label}
      {props.children({ id, 'aria-invalid': isInvalid })}
      {props.error && error}
    </div>
  );
}
저희는 지금 증강 아이템을 사용하여 전화를 걸고 있습니다props.children.이것은 렌더 도구 모드라고 불리며 the docs에서 더 많은 정보를 얻을 수 있습니다.이로 인해 다음과 같은 사용법이 발생합니다.
<InputGroup label="Amount">
  {inputProps => (
    <div>
      $ <input {...inputProps} />
    </div>
  )}
</InputGroup>
이렇게 하면 UI의 렌더링 방식을 완전히 제어할 수 있습니다.우리는 폼 입력에 도구를 제공하여 하위 함수의 매개 변수로 하고 사용자가 그것들을 정확한 요소에 배치하도록 할 것이다.
그러나 이런 방법은 문법이 엉망으로 보이기 때문에 소비자들이 수동으로 도구를 전파해야 한다는 단점도 있다.이것은 당신의 프로젝트에 있어서 좋은 모델인지 고려해 보세요.

요약


React 어셈블리에 대해 신뢰할 수 있는 API를 생성하는 것은 결코 쉬운 일이 아닙니다.구성 요소는 서로 다른 사용자에게 다시 사용될 수 있어야 한다. 기본적으로 모든 것은 접근할 수 있어야 하고, 구성 요소가 하는 모든 일은 다시 쓸 수 있어야 한다.
본고는 몇 가지 목적지에 도달하는 방법을 소개하였다.그것은 확실히 일을 좀 복잡하게 만들지만, 매주 구성 요소에 새로운 도구를 추가할 필요가 없이 아주 유연한 UI를 만들 수 있다.
이 API를 사용하려면 다음 코드 샌드박스에서 사용할 수 있습니다.
읽어주셔서 감사합니다!

좋은 웹페이지 즐겨찾기