[JavaScript] 커리 아니고 커링

jade·2025년 7월 22일

Javascript 디자인 패턴 : 커링패턴

여러개의 입력을 받는 함수를 한개의입력만 받는 여러개의 함수로 변환하는 것이다. 유연한 함수를 선언해 재사용성을 향상시킬 수 있지만, 성능이슈가 발생할 수 있다.

커링패턴은 함수영 프로그래밍에서 자주 사용되는 기법 중 하나인데 하스켈이나 스칼라 같은 함수형 프로그래밍 언어에는 기본적으로 내장되어 있다고 한다. 자바스크립트의 유연한 문법으로 이를 구현할 수 있다.

장점

  • 일부 매개변수를 미리 설정하고 나머지 매개변수에 대해서는 나중에 처리함으로써 함수의 재사용성이 높아짐
  • 크고 복잡한 함수를 작고 관리하기 쉬운 단위로 분할

단점

  • 매개 변수가 많아질 수록 추가적인 함수호출과 메모리할당을 발생시켜 성능이슈가 발생
  • 함수 호출 구조가 복잡해지고 여러단계로 나뉘어 있어서 추적이 더 어려워질 수 있음.

커링함수 예시

const applyDiscount = (할인율) => (가격) => 가격 - 가격 * 할인율

// 1. 변동성이 낮은 인자를 우선으로 받고, 높은 인자는 뒷순서로 받는 것이 좋다.
// 할인율이 0.1이라는 것을 기억하는 클로저
const tenPercentDiscount = applyDiscount(0.1)
// 두번째 인자를 나중에 전달하여 함수를 지연실행
const discountedPrice = tenPercentDiscount(1000)
console.log(discountedPrice)

// 2. 연속해서 호출 가능
const directlyDiscountedPrice = applyDiscount(0.1)(1000)
console.log(directlyDiscountedPrice)

활용하기

이벤트 핸들러 간소화

더 이상 onClick={(e) => handleItemClick(itemId)} 와 같이 선언하지 않아도 된다.

function Component() {

    const handleItemClick = itemId => (event) => {
        console.log(itemId, event.target.value)
    }

    return (
        <div>
            {['item1', 'item2', 'item3'].map(itemId => (
                <button key={itemId} onClick={handleItemClick(itemId)}>
                    Click {itemId}
                </button>
            ))}
        </div>
    )
}

api 호출처리

const createEndPoint = (base) => endpoint => params => {
    const query = new URLSearchParams(params).toString();
    return `${base}/${endpoint}?${query}`
}

// 기본 api url
const baseAPI = createEndPoint('https://example.com/api');

// 엔드포인트 확장
const fetchUser = baseAPI('users');
const fetchPost= baseAPI('posts');


const userAPIPath = fetchUser({id: 1, name: 'lee'});

고차 컴포넌트

// 커링 함수를 이용한 HOC 선언
function withLoading(WrappedComponent) {
    return function({ isLoading, ...rest }) {
        if (isLoading) {
            return <div>Loading...</div>;
        } else {
            return <WrappedComponent {...rest} />;
        }
    };
}

// 예시 컴포넌트 선언
function MyComponent({ data }) {
    return (
        <div>
            <h1>My Component</h1>
            <p>{data}</p>
        </div>
    );
}

// 사용 예시
const MyComponentWithLoading = withLoading(MyComponent);

function App() {
    // 데이터를 가져오는 상태 시뮬레이션
    const [loading, setLoading] = useState(true);
    const [data, setData] = useState(null);


    return (
        <MyComponentWithLoading isLoading={loading} data={data} />
    );
}

팩토리 패턴

// 커링 함수를 사용한 컴포넌트 생성 함수
const createComponent = (Component) => (properties) => {
    return <Component {...properties} />;
};

// 커링 함수 사용하여 특정 컴포넌트 생성 함수 만들기
const createButton = createComponent("button"); // HTML button 요소
const createLabel = createComponent("label"); // HTML label 요소

// 개별 컴포넌트 생성
const BlueButton = () =>
    createButton({ style: { color: "blue" }, children: "Click me" });
const LargeLabel = () =>
    createLabel({ style: { fontSize: "large" }, children: "Label text" });

// 사용 예시
function App() {
    return (
        <div>
            <BlueButton />
            <LargeLabel />
        </div>
    );
}

validator

유효성 검사를 하기 위해 필요가 값은 크게 두가지 인데

  • 유효한 범위를 결정지은 값 (1번)
  • 실제 입력된 값 (2번)

커링함수를 이용하여 1번이 결정된 함수를 미리 만들어 두고, 함수의 실행은 실제로 값이 입력된 시점에 이루어지도록 하는 방법이다.

// 커링함수를 사용한 유효성 검사 함수
const minLength = (min: number) => (value: string) => {
    return value.length >= min ? undefined : `최소 ${min}글자 이상 입력해주세요.`;
}

const maxLength = (max: number) => (value: string) => {
    return value.length <= max ? undefined : `최대 ${max}글자 이하로 입력해주세요.`;
}


// 컴포넌트를 사용하는 쪽에서 첫번째 인자를 전달.
<TextField
        source="name"
        label="이름"
        validateArray={[minLength(2), maxLength(6)]}
/>


// TextField 내부에서 useEffect를 통해 값이 입력될때
// 모든 유효성 검사가 이루어지게끔 함.
React.useEffect(() => {
    const errors = validateArray.map((validateFn: any, _i: number) => {
      if(value[source] !== undefined){
        return validateFn(value[source]);
      }
    })

    const filteredErrors = errors.find((error: any) => error !== undefined);
    setError(filteredErrors);

  }, [value[source]]);

profile
keep on pushing

0개의 댓글