호출 부분
const MemberOfGuest = withMemberGuest(props => {
const {onClick, value} = props;
return <SearchInput icon="member" onClick={onClick} defaultValue={value} isReadonly={true} readOnly />;
});
구현 부분
타입 및 인터페이스 정의
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;
}
상수 및 초기 값 정의
const defaultAgeValue = [
{ text: "만 1세 미만", value: 0 },
{ text: "만 1세", value: 1 },
// ...
];
const defaultValue: GuestMemberInfo[] = [{ adt: 2, chd: [] }];
컴포넌트 정의(비지니스 로직)
const AgeOption = props => { ... };
const GuestMember = ({ guest }: { guest: GuestModify }) => { ... };
const Layer = props => { ... };
고차 컴포넌트 정의
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;
};
렌더링 및 타입 지정
export default withMemberGuest;
export type { MemberGuestRef, GuestMemberInfo };