Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#25] 사용자가이드 단계 이동시 헤더 내 모든 요소 리렌더링 개선 #37

Merged
merged 8 commits into from
Jan 24, 2025
1 change: 1 addition & 0 deletions apps/client/src/entities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ export { ImageTagModalImg } from './workspace/ImageTagModalImg/ImageTagModalImg'
export { ImageTagModalButton } from './workspace/ImageTagModalButton/ImageTagModalButton';
export { ImageTagModalListItem } from './workspace/ImageTagModalListItem/ImageTagModalListItem';
export { CodeExportButton } from './workspace/CodeExportButton/CodeExportButton';
export { HelpButton } from './workspace/HelpButton/HelpButton';
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Spinner } from '@/shared/ui';
import { exportPreviewHtml } from '@/shared/utils';
import toast from 'react-hot-toast';
import { useState } from 'react';
import { memo, useState } from 'react';

export const CodeExportButton = () => {
export const CodeExportButton = memo(() => {
const [isLoading, setIsLoading] = useState(false);

const handleClick = () => {
Expand Down Expand Up @@ -32,4 +32,4 @@ export const CodeExportButton = () => {
)}
</button>
);
};
});
22 changes: 22 additions & 0 deletions apps/client/src/entities/workspace/HelpButton/HelpButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Question from '@/shared/assets/question.svg?react';
import { useCoachMarkStore } from '@/shared/store/useCoachMarkStore';
import { memo } from 'react';
import { useShallow } from 'zustand/react/shallow';

export const HelpButton = memo(() => {
const { openCoachMark } = useCoachMarkStore(
useShallow((state) => ({
openCoachMark: state.openCoachMark,
}))
);

return (
<button
className="text-medium-rg hover flex items-center gap-1 text-gray-300 hover:text-gray-500"
onClick={openCoachMark}
aria-label="도움말 버튼"
>
도움말 <Question />
</button>
);
});
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { CircleButton } from '@/shared/ui';
import RightArrow from '@/shared/assets/arrow_right.svg?react';
import { useWorkspaceStore } from '@/shared/store';
import { memo } from 'react';

/**
* @description
* 워크스페이스 캔버스에서 redo 기능을 실행시키는 버튼입니다.
*/
export const RedoButton = () => {
export const RedoButton = memo(() => {
const { workspace } = useWorkspaceStore();

const handleRedo = () => {
Expand All @@ -20,4 +21,4 @@ export const RedoButton = () => {
<RightArrow />
</CircleButton>
);
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import { cssStyleToolboxConfig } from '@/shared/blockly';
import toast from 'react-hot-toast';
import { useParams } from 'react-router-dom';
import { useSaveWorkspace } from '@/shared/hooks';
import { useState } from 'react';
import { memo, useState } from 'react';

/**
*
* @description
* Workspace 상태를 저장하는 버튼입니다.
* 저장 항목 : css 속성, 캔버스 블록 상태, css class 블록, css 리셋 여부, 미리보기 썸네일
*/
export const SaveButton = () => {
export const SaveButton = memo(() => {
const workspaceId = useParams().workspaceId as string;
const { mutate: saveWorkspace, isPending } = useSaveWorkspace(workspaceId);
const { totalCssPropertyObj } = useCssPropsStore();
Expand Down Expand Up @@ -63,4 +63,4 @@ export const SaveButton = () => {
</button>
</>
);
};
});
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { CircleButton } from '@/shared/ui';
import LeftArrow from '@/shared/assets/arrow_left.svg?react';
import { useWorkspaceStore } from '@/shared/store';
import { memo } from 'react';

/**
*
* @description
* 워크스페이스 캔버스에서 undo 기능을 실행시키는 버튼입니다.
*/
export const UndoButton = () => {
export const UndoButton = memo(() => {
const { workspace } = useWorkspaceStore();

const handleUndo = () => {
Expand All @@ -21,4 +22,4 @@ export const UndoButton = () => {
<LeftArrow />
</CircleButton>
);
};
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FocusEventHandler, KeyboardEventHandler, useEffect, useState } from 'react';
import { FocusEventHandler, KeyboardEventHandler, memo, useEffect, useState } from 'react';

import { Spinner } from '@/shared/ui';
import { useParams } from 'react-router-dom';
Expand All @@ -9,7 +9,7 @@ import { useWorkspaceStore } from '@/shared/store';
* @description
* 워크스페이스 이름을 수정할 수 있는 컴포넌트입니다.
*/
export const WorkspaceNameInput = () => {
export const WorkspaceNameInput = memo(() => {
const { workspaceId } = useParams() as { workspaceId: string };
const { mutate, isPending } = useUpdateWorkspaceName();
const { name } = useWorkspaceStore();
Expand Down Expand Up @@ -68,4 +68,4 @@ export const WorkspaceNameInput = () => {
</div>
</>
);
};
});
11 changes: 9 additions & 2 deletions apps/client/src/pages/Workspacepage/WorkspacePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useGetWorkspace, usePreventLeaveWorkspacePage } from '@/shared/hooks';

import { useCoachMarkStore } from '@/shared/store/useCoachMarkStore';
import { useParams } from 'react-router-dom';
import { useShallow } from 'zustand/react/shallow';

/**
*
Expand All @@ -14,7 +15,13 @@ export const WorkspacePage = () => {
const { workspaceId } = useParams();
useGetWorkspace(workspaceId as string);
usePreventLeaveWorkspacePage();
const { currentStep, isCoachMarkOpen, openCoachMark } = useCoachMarkStore();
const { currentStep, isCoachMarkOpen, openCoachMark } = useCoachMarkStore(
useShallow((state) => ({
currentStep: state.currentStep,
isCoachMarkOpen: state.isCoachMarkOpen,
openCoachMark: state.openCoachMark,
}))
);
const toolboxDiv = document.querySelector('.blocklyToolboxDiv');

useLayoutEffect(() => {
Expand All @@ -39,7 +46,7 @@ export const WorkspacePage = () => {
<>
<div className="flex h-screen flex-col">
{isCoachMarkOpen && <CoachMark />}
<WorkspacePageHeader />
<WorkspacePageHeader currentStep={currentStep} />
<WorkspaceContent />
</div>
<ImageTagModal />
Expand Down
5 changes: 3 additions & 2 deletions apps/client/src/shared/ui/logo/Logo.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import BlackLogoText from '@/shared/assets/boolock_logo_black.svg?react';
import { Link } from 'react-router-dom';
import WhiteLogoText from '@/shared/assets/boolock_logo_white.svg?react';
import { memo } from 'react';

type LogoProps = {
isBlack: boolean;
Expand All @@ -11,7 +12,7 @@ type LogoProps = {
* @description
* 로고 컴포넌트 (흰색/검은색), 클릭 시 홈페이지로 이동
*/
export const Logo = ({ isBlack }: LogoProps) => {
export const Logo = memo(({ isBlack }: LogoProps) => {
return (
<Link to="/">
<div className="flex items-center gap-3">
Expand All @@ -25,4 +26,4 @@ export const Logo = ({ isBlack }: LogoProps) => {
</div>
</Link>
);
};
});
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { CodeExportButton, RedoButton, SaveButton, UndoButton } from '@/entities';
import { memo } from 'react';

import { useCoachMarkStore } from '@/shared/store/useCoachMarkStore';
type TWorkspaceHeaderButtons = {
currentStep: number;
};

export const WorkspaceHeaderButtons = memo(({ currentStep }: TWorkspaceHeaderButtons) => {
const buttonsClassName = `flex items-center gap-3 ${currentStep === 4 ? 'z-[99999]' : ''}`;

export const WorkspaceHeaderButtons = () => {
const { currentStep } = useCoachMarkStore();
return (
<div className={`flex items-center gap-3 ${currentStep === 4 ? 'z-[99999]' : ''}`}>
<div className={buttonsClassName}>
<CodeExportButton />
<SaveButton />
<UndoButton />
<RedoButton />
</div>
);
};
});
Original file line number Diff line number Diff line change
@@ -1,33 +1,36 @@
import { WorkspaceNameInput } from '@/entities';
import { HelpButton, WorkspaceNameInput } from '@/entities';
import { Logo } from '@/shared/ui';
import { WorkspaceHeaderButtons } from '../WorkspaceHeaderButtons/WorkspaceHeaderButtons';
import { useCoachMarkStore } from '@/shared/store/useCoachMarkStore';
import Question from '@/shared/assets/question.svg?react';
import { memo } from 'react';

/**
*
* @description
* 워크스페이스 페이지 헤더 컴포넌트
*/
export const WorkspacePageHeader = () => {
const { openCoachMark } = useCoachMarkStore();

return (
<div className="flex h-14 w-full flex-shrink-0 items-center justify-between border-b border-gray-100 bg-white pl-8 pr-4">
<div className="flex items-center gap-5">
<Logo isBlack={false} />
<WorkspaceNameInput />
</div>
<div className="flex gap-11">
<button
className="text-medium-rg hover flex items-center gap-1 text-gray-300 hover:text-gray-500"
onClick={openCoachMark}
aria-label="도움말 버튼"
>
도움말 <Question />
</button>
<WorkspaceHeaderButtons />
</div>
</div>
);
type TWorkspacePageHeader = {
currentStep: number;
};

export const WorkspacePageHeader = memo(
({ currentStep }: TWorkspacePageHeader) => {
return (
<div className="flex h-14 w-full flex-shrink-0 items-center justify-between border-b border-gray-100 bg-white pl-8 pr-4">
<div className="flex items-center gap-5">
<Logo isBlack={false} />
<WorkspaceNameInput />
</div>
<div className="flex gap-11">
<HelpButton />
<WorkspaceHeaderButtons currentStep={currentStep} />
</div>
</div>
);
},
(prevProps, nextProps) => {
const prevIsFour = prevProps.currentStep !== 4;
const nextIsFour = nextProps.currentStep !== 4;
return prevIsFour && nextIsFour;
}
);
Loading