위코드 기업협업에 참여하며 정리한 내용입니다.
특정 영역을 클릭하면 해당 영역이 포커스되면서 강조 표시가 유지되고, 그 영역에 맞는 컴포넌트를 불러와서 우측에 띄워주는 기능을 아래처럼 구현했다. View 컴포펀트 안에 ViewNav 는 아래와 같은 형태를 가지는데, 태일윈드를 사용했으므로 삼항연산자로 id 값을 비교해 클래스를 추가하는 방식을 적용했다. 하지만 간혹 적용되지 않는 스타일은, 클래스 명 변경으로 반영이 되지 않아서 별도 인라인 스타일을 사용했다.(이렇게 변화가 적용되지 않는 속성이 몇몇 있는 것 같음) focusId 를 결정하는 sectionClick 함수는 View 컴포넌트에서 전달하는 데 해당 함수는 클릭한 타겟의 id 를 저장하므로 ViewNav 의 div 가 가진 id 값을 가져오게 된다.
// ViewNav.tsx
interface NavDataProps { // 아래 컴포넌트가 인자로 전달받은 데이터의 타입
data?: NavData; // NavData 는 다른 곳에서 정의한 데이터 타입을 불러와 사용한 것
focusId: string;
sectionClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
}
const ViewNav = ({ data, focusId, sectionClick }: NavDataProps) => {
if (!data) return <>loading...</>; // 데이터가 없을 경우 로딩
// 전달받은 데이터를 구조분해할당
const { box_image_url, menu_list, bg_color, section_title_color } = data;
return (
<div
id="nav" // 이 id 가 아래 onClick 함수로 전달되어서 focusId 로 세팅되는 것
className={`flex justify-between items-center ...
// 삼항연산자로 전달받은 id 를 비교해
${focusId === "nav" ? "border-2 border-main_purple scale-[1.01]" : ""}`}
style={{ backgroundColor: `${bg_color}` }} // 클래스로 적용 안될 경우 인라인 스타일 사용
onClick={sectionClick}
>
...
</div>
);
};
export default ViewNav;
// View.tsx
const sectionClick = (e: MouseEvent<HTMLButtonElement>) => {
const target = e.currentTarget.id; // 클릭한 요소의 id 를 담아
return setFocusId(target); // focusId 로 세팅
};
이렇게 저장한 Id 값인 focusId 를 사용해 특정 컴포넌트를 불러오는데, 일단 focusId 를 해당 하위 컴포넌트에 프롭으로 전달하고 그 id 와 컴포넌트를 매칭한 배열을 만들어 find 메서드로 해당 요소의 id 와 focusId 가 같은 요소를 추출합니다. 그리고 그 컴포넌트를 화면에 출력합니다.
const EditPanel = ({ focusId, onApplyClickEvent }: ClickEventProps) => {
...
// id 별로 보여줄 컴포넌트 정리
const EDIT_PANEL = [
{ id: "nav", panels: EditPanelNav },
{ id: "main", panels: EditPanelMain },
{ id: "imageSlide", panels: EditPanelImageSlider },
{ id: "leftTextRightImage", panels: EditPanelLeftRightImage },
{ id: "textCard", panels: EditPanelTextCard },
{ id: "introText", panels: EditPanelIntroText },
{
id: "leftTextRightMultiImages",
panels: EditPanelLeftTextRightMultiImages,
},
{ id: "textSlide", panels: EditPanelTextSlide },
{ id: "footer", panels: EditPanelFooter },
];
// id 를 비교해서 보여줄 컴포넌트 선택
const focusEditPanel: any = EDIT_PANEL.find((item) => item.id === focusId);
return (
<div className="ml-5 ">
...
<div className="sticky top-8">
<div className="w-[500px] p-10 text-sm bg-white shadow-md ">
// foucsId 여부에 따라 해당 요소를 보여주거나 디폴트 화면을 보여줌
{focusId.length !== 0 ? (
<focusEditPanel.panels
editInfo={editInfo}
updateEditInfo={updateEditInfo}
/>
) : (
<EditPanelDefault />
)}
</div>
...
</div>
</div>
);
};
export default EditPanel;