사용자 인터페이스용 제네릭

특정 리소스 목록을 관리하는 코드를 얼마나 자주 작성합니까? 이것이 얼마나 흔한 일인지에도 불구하고 나는 종종 동일한 코드베이스에서 수십 개를 설정하기 위한 좋은 패턴을 찾기 위해 고군분투했습니다. 레시피, 팀원, 송장을 너무 많이 반복하지 않고 관리합니다. 최근에 TypeScript에서 힌트를 얻어 React에서 마침내 만족스러운 것을 설정했습니다.

기본적으로 TypeScript가 이것을 잘 처리한다면:

interface Recipe {
  title: string
  description: string
}

type Recipes = Array<Recipe>


그런 다음 React와 같은 TypeScript 친화적인 프런트엔드 프레임워크는 확실히 다음을 수행할 수 있습니다.

// We get to RecipeEditorProps later in the post
const RecipeEditor: React.FC<RecipeEditorProps> = () => (
  <div>
    {/* TBA */}
  </div>
)

const RecipeListEditor: React.FC<RecipeListEditorProps> = () => (
  <div>
    {/* Some abstraction involving <RecipeEditor/> */}
  </div>
)


tldr here is a CodeSandbox을 보고 싶은 사람들을 위한 것입니다.

리소스를 담당하는 구성 요소를 가져 와서 리소스 목록을 처리하는 구성 요소로 바꾸는 현명한 추상화는 무엇입니까? 더 나은 단어가 없기 때문에 이를 일반 UI라고 부르겠습니다. 특정 불특정 유형으로 구성된 구조에서 작동하는 것입니다.

FP enthusiasts might get excited about fancier names like functor UIs or UI lifting, but I will hold off on those for the time being.



레시피 편집기



레시피 편집을 담당하는 구성 요소는 다음과 같습니다.

interface RecipeEditorProps {
  value: Recipe
  onChange: (newRecipe: Recipe) => void
}

const RecipeEditor: React.FC<RecipeEditorProps> = (props) => (
  <div>
    <input
      value={props.value.title}
      onChange={(ev: ChangeEvent<HTMLInputElement>) => {
        props.onChange({
          ...props.value,
          title: ev.target.value
        });
      }}
    />
    <input
      value={props.value.description}
      onChange={(ev: ChangeEvent<HTMLInputElement>) => {
        props.onChange({
          ...props.value,
          description: ev.target.value
        });
      }}
    />
  </div>
);


이를 통해controlled component 부모가 문제의 리소스를 관리할 수 있으므로 구성 요소 계층 구조에서 상태를 충분히 유연하게 관리할 수 있습니다.

목록으로 결합



이 간단한 편집기를 기반으로 리소스 목록을 만들 수 있습니다. 리소스 목록을 매핑하고 변경 이벤트를 연결하여 올바른 인덱스에서 목록을 (불변하게) 업데이트하고 일부 삭제 버튼을 사용하여 마무리할 수 있습니다. 여기에 몇 가지 코드를 추가할 수 있지만 그 시점에서 더미에 또 다른 React todo 목록 튜토리얼을 추가했습니다.

대신 노드 내부에 무엇이 있는지 신경 쓰지 않는 목록 관리자 구성 요소를 살펴보겠습니다.

일반 목록 편집기 추상화



이 추상ListEditor 구성 요소는 리소스 편집기 구성 요소를 소품으로 사용하고 나머지 작업을 수행합니다. 다음은 이러한 구성 요소의 소품에 대한 몇 가지 유형 정의입니다.

export interface Props<T> {
  values: Array<T>;
  onChange: (newValues: Array<T>) => void;
  newValue: () => T;
  newValueLabel?: string;
  Editor: React.FC<EditorProps<T>>;
}

// The props for the item editor, parameterized by T
export interface EditorProps<T> {
  value: T;
  onChange: (newValue: T) => void;
}


이 시점에서 모든 것은 T 로 매개변수화되며 나중에 Recipe , User 등으로 채울 수 있습니다. valuesonChange 외에도 구성 요소에는 몇 가지 주변 소품이 필요합니다. 추가 버튼을 클릭할 때 새 값을 생성하고 해당 버튼에 포함되어야 하는 레이블입니다.

구현은 대략 다음과 같습니다.

function ListEditor<T>(props: Props<T>) {
  return (
    <div>
      <div>
        {props.values.map((item, index) => (
          <div>
            <props.Editor
              value={item}
              onChange={(newItem) => {
                // Use a helper to immutably change item at an index
                props.onChange(setAt(index, newItem, props.values));
              }}
            />
            <button
              onClick={() => {
                // Use a helper to immutably remove an item at an index
                props.onChange(removeAt(index, props.values));
              }}
            >
              Delete
            </button>
          </div>
        )}
      </div>
      <button
        onClick={() => {
          props.onChange([...props.values, props.newValue()]);
        }}
      >
        {props.newValueLabel || "Add new"}
      </button>
    </div>
  );
}


마지막으로 적절한 소품을 사용하여 <props.Editor /> 인스턴스를 인스턴스화하고 이 구성 요소가 사용되는 모든 위치에서 일관되게 보이는 추가 및 삭제 버튼과 같은 모든 주변 UI를 추가합니다.

평화롭게 UX 상품 추가



이제 일반 목록 편집기 구성 요소가 있으므로 코드베이스의 모든 단일 목록 편집기에 전파된다는 것을 알고 멋진 UX 기능을 추가할 수 있습니다.

CodeSandbox에서 레시피 목록과 사용자 목록 모두에 대해 간단한 재정렬을 허용하도록 react-beautiful-dnd를 추가했습니다. 개별 편집자는 자신이 밀리고 있다는 사실을 결코 알지 못했습니다 🤓.



결론



이것으로 무엇을 할 수 있습니까? 나는 패턴이 가져오기 가능한 패키지의 일종으로 이치에 맞지 않는다고 생각합니다. 여전히 스타일이 지정된 UI 코드와 상당히 결합되어 있으며 분리하면 멋진 사용자 지정 후크, 더 많은 사용자 지정 구성 요소 소품 또는 함수를 자식으로 사용할 수 있습니다. . 프로젝트에서 수십 줄의 코드를 설정하고 필요에 맞게 사용자 지정하는 것이 더 나을 것이라고 생각합니다.

아마도 더 중요한 것은 사물 자체가 무엇인지 알 필요 없이 사물 집합을 관리하는 구성 요소라는 일반적인 개념일 것입니다. 이러한 종류의 분리 덕분에 complex projects well beyond lists에 대한 유지 관리 작업 시간이 많이 절약되었습니다. 여러분에게도 도움이 되었기를 바랍니다!

좋은 웹페이지 즐겨찾기