개체 설정을 사용하여 태그 필드 만들기

13485 단어 reactjavascript
태그 입력은 구분 기호(보통 스페이스바 또는 쉼표)를 입력할 때 새 태그를 추가하는 구성 요소입니다. 배열을 사용할 때 처리하기가 정말 성가신 중복을 허용하지 않습니다. 걱정하지 마세요. 세트가 우리를 도우러 왔습니다.

태그 구성 요소 만들기



이것은 약간 간단합니다. 삭제 버튼 표시를 토글하는 readOnly 와 해당 버튼을 클릭할 때 호출되는 함수인 onRemove 의 두 가지 props를 받는 상태 비저장 구성 요소입니다. 최종 결과는 다음과 같습니다.

interface TagProps {
  readOnly?: boolean;
  onRemove?: () => void;
}

const Tag: FC<TagProps> = ({ readOnly = false, onRemove, children }) => (
  <div className="tag">
    <small>{children}</small>
    {!readOnly && (
      <button onClick={onRemove}>
        <CloseIcon />
      </button>
    )}
  </div>
);


입력 생성



이제 재미있는 부분이 있습니다. 바로 태그 입력 자체입니다. 구성 요소는 다음을 수행해야 합니다. 모든 태그와 텍스트 필드를 렌더링하고, 특정 구분 문자가 입력될 때 새 태그를 추가하고, 중복 태그를 버리고, 선택적으로 백스페이스를 눌러 최신 태그를 제거해야 합니다. 예상되는 동작을 입력하면 상황이 훨씬 쉬워집니다(이것이 단위 테스트가 유용한 이유입니다).

기초



처음부터 시작합시다: Props. value (기본적으로 Set의 새 인스턴스로 설정됨) 및 onChange , 구성 요소를 제어 가능하게 만들기, separator (기본적으로 "," 로 설정) 태그 추가를 트리거하는 readOnly (기본적으로 false로 설정됨).

다음으로 컴포넌트 상태를 생성하겠습니다. tags 를 제어하려면 모든 값이 고유함을 보장하기 때문에 Set이 완벽합니다. 배열도 사용할 수 있지만 반복되는 태그를 수동으로 처리해야 합니다. 다음으로 텍스트 필드를 추가해야 합니다. 최종 결과가 일반적인 입력처럼 보이기를 원하기 때문에 모든 스타일을 제거하고 대신 상위 스타일div을 지정하겠습니다.

interface TagInputProps {
  onChange: (value: Set<string>) => void;
  value?: Set<string>;
  separator?: string;
  readOnly?: boolean;
}

const TagInput: FC<TagInputProps> = ({
  onChange,
  value = new Set(),
  separator = ",",
  readOnly = false
}) => {
  const [tags, setTags] = useState(value);
  const [inputValue, setInputValue] = useState("");

  return (
    <div className="tag-input">
      <input 
        value={inputValue} 
        onChange={({ target }) => setInputValue(target.value)}
      />
    </div>
  );
};


태그 추가



상태에 태그를 효과적으로 추가하기 위해 onKeyDown 이벤트를 처리할 것입니다. 누른 키( event.key )가 구분 기호와 같고 inputValue 가 비어 있지 않으면 해당 값을 tags 에 추가합니다. 코드로 번역:

const handleKeyDown = useCallback(
  (event) => {
    if (event.key === separator) {
      event.preventDefault();
      if (inputValue.trim().length > 0) {
        setTags((tags) => new Set([...tags, inputValue]));
        setInputValue("");
      }
    }
  },
  [separator, inputValue]
);


태그 제거



태그 삭제는 두 가지 방법으로 수행할 수 있습니다. 제거 버튼을 클릭하거나 커서가 있는 경우 백스페이스 키를 누릅니다.
텍스트 필드의 위치는 0입니다.

제거 버튼



여기에는 미스터리가 없습니다. tags 구성 요소의 onRemove 소품으로 설정된 Tag에서 항목을 제거하는 함수를 추가하기만 하면 됩니다.

onRemove={() => {
  const updatedTags = new Set(tags);
  updatedTags.delete(tag);
  setTags((tags) => updatedTags);
}}


백스페이스 누르기



다시 한 번 handleKeyDown 를 방문합니다. 먼저 prop backspaceErasetrue 로 설정되어 있는지 확인한 다음 Backspace가 눌렸는지, 캐럿이 위치 0에 있는지 확인합니다. 하지만 어떻게 할까요? selectionStart에서 selectionEndevent.target를 사용하여 : 텍스트를 선택하지 않고 커서가 시작 부분에 있는 경우 두 속성은 모두 0 가 됩니다. 이제 handleKeyDown는 다음과 같습니다.

const handleKeyDown = useCallback(
  (event) => {
    if (event.key === separator) {
      event.preventDefault();
      if (inputValue.trim().length > 0) {
        setTags((tags) => new Set([...tags, inputValue]));
        setInputValue("");
      }
    }
    if (backspaceErase && event.key === "Backspace") {
      const { selectionStart, selectionEnd } = event.target;
      if (selectionStart === 0 && selectionEnd === 0) {
        setTags((tags) => new Set([...tags].slice(0, -1)));
      }
    }
  },
  [separator, inputValue]
);


결과



음, 생각보다 쉬웠습니다. 결과는 아래 코드 샌드박스에서 볼 수 있습니다. 여기에 텍스트가 맞지 않는 경우에만 줄을 나누도록 입력 크기를 동적으로 조정하는 calcInputWidth 함수도 추가했습니다. 건배! 다음 글에서 만나요!

좋은 웹페이지 즐겨찾기