1. 호출 부분

    const MemberOfGuest = withMemberGuest(props => {
    	const {onClick, value} = props;
    	return <SearchInput icon="member" onClick={onClick} defaultValue={value} isReadonly={true} readOnly />;
    });
    
  2. 구현 부분

    1. 타입 및 인터페이스 정의

      type GuestMemberInfo = { adt: number; chd: (string | number)[] };
      
      interface Parameter {
        guestInfo?: GuestMemberInfo[];
        changeText?: (value: GuestMemberInfo[]) => string;
        callback?: (value: GuestMemberInfo[]) => void;
        isOpen?: (isOpen: boolean) => void;
        defaultValue?: string;
      }
      
      type GuestModify = {
        index: number;
        info: GuestMemberInfo;
        changeAdt: (adtCnt: number) => void;
        changeChd: (chdArray: (string | number)[]) => void;
      };
      
      interface MemberGuestRef {
        getId: string;
        text: string;
        value: GuestMemberInfo[];
        layerState: boolean;
        open: () => void;
      }
      
      • TypeScript를 사용하여 다양한 타입과 인터페이스를 정의합니다.
    2. 상수 및 초기 값 정의

      const defaultAgeValue = [
        { text: "만 1세 미만", value: 0 },
        { text: "만 1세", value: 1 },
        // ...
      ];
      
      const defaultValue: GuestMemberInfo[] = [{ adt: 2, chd: [] }];
      
      • 기본 나이 값 및 초기 게스트 정보를 정의합니다.
    3. 컴포넌트 정의(비지니스 로직)

      const AgeOption = props => { ... };
      const GuestMember = ({ guest }: { guest: GuestModify }) => { ... };
      const Layer = props => { ... };
      
      • 각각의 컴포넌트는 특정 기능을 수행
    4. 고차 컴포넌트 정의

      const withMemberGuest = WrappedComponent => {
      	const withComponent = forwardRef<MemberGuestRef, Parameter>((props, ref) => {
      		const {callback, defaultValue, guestInfo, isOpen, changeText} = props;
      		const [text, setText] = useState("");
      		const [selectValue, setSelectValue] = useState<GuestMemberInfo[]>(null);
      		const [searchLayer, setSearchLayer] = useState(false);
      		const id = useId();
      
      		useEffect(() => {
      			setText(defaultValue || "");
      		}, [defaultValue]);
      
      		useEffect(() => {
      			typeof isOpen === "function" && isOpen(searchLayer);
      		}, [searchLayer]);
      
      		useImperativeHandle(ref, () => ({
      			getId: id,
      			text,
      			layerState: searchLayer,
      			value: selectValue,
      			open: () => setSearchLayer(true),
      		}));
      
      		const onClick = useCallback(() => setSearchLayer(!searchLayer), []);
      		const changeValue = (value: GuestMemberInfo[]) => {
      			const guestCount = value.length;
      			const adtCount = value.reduce((acc, cur) => acc + cur.adt, 0);
      			const chdCount = value.reduce((acc, cur) => acc + cur.chd.length, 0);
      			setText(
      				typeof changeText === "function"
      					? changeText(value)
      					: `객실${guestCount} · 성인 ${adtCount}명 아동 ${chdCount}명`,
      			);
      			setSelectValue(value);
      			callback(value);
      		};
      
      		const wrappedProps = {
      			id,
      			onClick,
      			value: text,
      		};
      
      		return (
      			<>
      				<WrappedComponent {...wrappedProps} />
      				{searchLayer &&
      					createPortal(
      						<Layer
      							setSearchLayer={setSearchLayer}
      							parentText={setText}
      							parentValue={changeValue}
      							parentGuestInfo={guestInfo}
      						/>,
      						document.querySelector("#__searchArea"),
      					)}
      			</>
      		);
      	});
      
      	return withComponent;
      };
      
      • 고차 컴포넌트로서, 주어진 컴포넌트를 래핑하고 게스트 정보를 관리하는 데 사용됩니다.
    5. 렌더링 및 타입 지정

      export default withMemberGuest;
      export type { MemberGuestRef, GuestMemberInfo };