리액트 디자인 패턴은 함수형 코딩과 관련이 있다.

hojoon·2023년 11월 11일
0

느낀점

1주차 분량의 함수형 코딩 책을 읽으면서 이 책은 개발자로서 코딩을 잘하는 방법? 다른 동료와 협업을 잘하는 방법? 효율적이고 효과적이고 드라마틱한 코딩 하는 법을 알려주는 책은 아니라고 느꼈다.
이 책은 개발자로서 서비스를 만들고 설계할 때 하나의 좋은 길을 제시해주는 책이라고 느꼈습니다. 또한 핵심은 각각의 함수는 독립적이어야 하고 (의존적이지 않고) 재사용 가능하다 라는게 핵심이다고 생각했습니다.

React

독립적이고 재사용 가능한 함수들을 조립하고 분해하는게 리액트의 컴포넌트들과 많이 닮아있다고 생각했음(이름도 함수형 컴포넌트임)
그래서 찾아보면 리액트에서 효과적이고 좋은 설계를 위한 몇가지 디자인 패턴이 존재하는데 오늘은 이것을 소개해보도록 하겠습니다.

1. 합성 컴포넌트

합성 컴포넌트 패턴은 하나의 컴포넌트를 여러 가지 집합체로 분리한 뒤, 분리된 각 컴포넌트를 사용하는 쪽에서 조합해 사용하는 컴포넌트 패턴을 의미합니다.

기존의 props 패턴

<Dialog
    dimmed
    title="타이틀"
    checkBoxList={[
        {
            title: '버튼명',
            isChecked: true,
            hasArrowButton: true,
        },
          {
            title: '버튼명',
            isChecked: false,
            hasArrowButton: true,
        },
          {
            title: '버튼명',
            isChecked: false,
            hasArrowButton: true,
        },
          {
            title: '버튼명',
            isChecked: false,
            hasArrowButton: true,
        },
          {
            title: '버튼명',
            isChecked: false,
            hasArrowButton: true,
        },
    ]}
    labelButtonList={[
        { 
            title: '버튼레이블',
        }
    ]}
/>

합성 컴포넌트 패턴

<Dialog>
  <Dialog.Dimmed />
  <Dialog.Title>타이틀</Dialog.Title>
  <Dialog.CheckBox isChecked hasArrowButton>
    버튼명
  </Dialog.CheckBox>
  <Dialog.CheckBox hasArrowButton>버튼명</Dialog.CheckBox>
  <Dialog.CheckBox hasArrowButton>버튼명</Dialog.CheckBox>
  {/* 혹시 여기에 무언가 설명이 들어가야 한다면 아래처럼 추가만 하면 됩니다. 더이상 이미 구현된 Dialog를 수정할 필요는 없습니다.
    <Dialog.Description>설명</Dialog.Description> 
  */}
  <Dialog.CheckBox hasArrowButton>버튼명</Dialog.CheckBox>
  <Dialog.CheckBox hasArrowButton>버튼명</Dialog.CheckBox>
  <Dialog.LabelButton>버튼레이블</Dialog.LabelButton>
</Dialog>

컴포넌트 설계 부분

export const Dialog = Object.assign(DialogMain, {
  Dimmed: DialogDimmed,
  Title: DialogTitle,
  Subtitle: DialogSubtitle,
  Description: DialogDescription,
  Comment: DialogComment,
  CheckButton: DialogCheckButton,
  CheckBox: DialogCheckBox,
  TextButton: DialogTextButton,
  Button: DialogButton,
  LabelButton: DialogLabelButton,
  Divider: DialogDivider,
});

// Usage
<Dialog>
    <Dialog.Title>제목</Dialog.Title>
</Dialog>

2. Container and Presentational Components Pattern

적용전

function SearchForm() {

    const [searchKey, setSearcKey] = useState();

    function onChange(event) {
        setSearcKey(event.target.value);
    }

    function onSubmit(event) {
        event.preventDefault();
        console.log(searchKey);
    }

    return (
        <form onSubmit={onSubmit}>
            <div>
                <label>제목</label>
                <input type="text" value={searchKey} onChange={onChange} name="searchKey"/>
                <button type="submit">검색</button>
            </div>
        </form>
    )
}

export default SearchForm;

적용 후

// Presentation Component
function SearchFormView() {

    const {searchKey, onChange, onSubmit} = props;

    return (
        <form onSubmit={onSubmit}>
            <div>
                <label>제목</label>
                <input type="text" value={searchKey} onChange={onChange} name="searchKey"/>
                <button type="submit">검색</button>
            </div>
        </form>
    )
}
export default SearchFormView;
// Container Component
function SearchFormContainer() {

    const [searchKey, setSearcKey] = useState();

    function onChange(event) {
        setSearcKey(event.target.value);
    }

    function onSubmit(event) {
        event.preventDefault();
        console.log(searchKey);
    }

    return (
        <SearchFormView
            searchKey={searchKey}
            onChange={onChange}
            onSubmit={onSubmit}
        />
    )
}

export default SearchFormContainer;

중요한 것은

presentation 컴포넌트는 단순히 데이터, 상태 값만을 바라보고 어떤 기능을 하지 않는다 (데이터를 기반으로한 디자인만을 담당함)
Container 컴포넌트에서 여러가지 로직을 담당한다. 디자인은 전혀 담당하지 않는다.

Custom Hooks

책을 읽으면서도 나왔던 util 함수와도 비슷한 개념이지 않을까 싶습니다.!

  • 훅으로 로직을 분리하여 재사용을 가능하게 만든다.
// Hooks
export default function useSearch() {

    const [searchKey, setSearcKey] = useState();

    
    function onChange(event) {
        setSearcKey(event.target.value);
    }

    function onSubmit(event) {
        event.preventDefault();
        console.log(searchKey);
    }

    return {
        searchKey,
        onChange,
        onSubmit,
    }
}
function SearchForm() {

    const { searchKey, onChange, onSubmit } = useSearch();

    return (
        <form onSubmit={onSubmit}>
            <div>
                <label>제목</label>
                <input type="text" value={searchKey} onChange={onChange} name="searchKey"/>
                <button type="submit">검색</bu![](https://velog.velcdn.com/images/ghwns1007/post/1dc10787-b099-4a99-b838-5645db9a1909/image.png)
tton>
            </div>
        </form>
    )
}

export default SearchForm;

아토믹 디자인 패턴

  • 디자인을 계층적으로 정의함으로써, 일관성을 유지하고 관리가 쉽도록 한다.
  • 5계층으로 나누는데 최소 계층부터 아톰, 뮬리클, 오거니즘, 템플릿, 페이지 를 조합해서 요소를 구성함

언제 사용할 수 있을까?

  • 프로젝트를 시작할 때 레이아웃? 여러 컴포넌트 들을 설계할 때 적용해보면 나중에 기능 개발하면서 갈아엎어야 하는 불행을 방지할 수 있고 단순히 따라만 해도 좋다. 막막하지 않고

사용 경험

이 밖에도 존재하는 여러가지 디자인 패턴들

  • 제어 컴포넌트와 비제어 컴포넌트
  • HOC
  • render props 패턴
  • prop collections pattern
  • react children pattern
  • command 패턴

https://velog.io/@youngcheon/toss-slash-23-funnel

profile
프론트? 백? 초보 개발자의 기록 공간

0개의 댓글