사이드바 컴포넌트 개발#27
Conversation
Summary of ChangesHello @jungwon123, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 이 PR은 애플리케이션의 사이드바 기능을 구현하기 위한 포괄적인 컴포넌트 세트를 도입합니다. 데스크톱 및 모바일 환경 모두에서 사용자에게 일관되고 반응형 탐색 경험을 제공하는 것을 목표로 하며, 재사용 가능한 UI 요소들을 통해 향후 확장성을 고려하여 설계되었습니다. 이를 통해 사용자 인터페이스의 전반적인 구조와 접근성이 향상될 것입니다. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
| useEffect(() => { | ||
| if (!isOpen || !drawerRef.current) return; | ||
|
|
||
| focusableRef.current = Array.from( | ||
| drawerRef.current.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR), | ||
| ); | ||
|
|
||
| const handleKeyDown = (e: KeyboardEvent) => { | ||
| if (e.key === 'Escape') { | ||
| onClose(); | ||
| return; | ||
| } | ||
|
|
||
| if (e.key !== 'Tab') return; | ||
|
|
||
| const items = focusableRef.current; | ||
| if (items.length === 0) return; | ||
|
|
||
| const first = items[0]; | ||
| const last = items[items.length - 1]; | ||
|
|
||
| if (e.shiftKey && document.activeElement === first) { | ||
| e.preventDefault(); | ||
| last.focus(); | ||
| } else if (!e.shiftKey && document.activeElement === last) { | ||
| e.preventDefault(); | ||
| first.focus(); | ||
| } | ||
| }; | ||
|
|
||
| document.addEventListener('keydown', handleKeyDown); | ||
| return () => document.removeEventListener('keydown', handleKeyDown); | ||
| }, [isOpen, onClose]); |
There was a problem hiding this comment.
현재 useEffect 훅이 onClose 함수에 의존하고 있습니다. 만약 부모 컴포넌트에서 onClose prop을 useCallback으로 감싸지 않으면, 부모가 리렌더링될 때마다 새로운 함수가 생성되어 이 useEffect가 불필요하게 재실행될 수 있습니다. 이는 성능 저하의 원인이 될 수 있습니다.
이러한 문제를 방지하고 컴포넌트의 안정성을 높이기 위해, onClose 함수를 ref에 저장하여 사용하는 것을 고려해볼 수 있습니다. 이렇게 하면 useEffect는 isOpen 상태가 변경될 때만 실행되면서도 항상 최신의 onClose 함수를 호출할 수 있습니다.
export default function MobileDrawer({ isOpen, children, onClose }: MobileDrawerProps) {
const drawerRef = useRef<HTMLElement>(null);
const focusableRef = useRef<HTMLElement[]>([]);
const onCloseRef = useRef(onClose);
useEffect(() => {
onCloseRef.current = onClose;
}, [onClose]);
useEffect(() => {
if (!isOpen || !drawerRef.current) return;
focusableRef.current = Array.from(
drawerRef.current.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR),
);
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
onCloseRef.current();
return;
}
if (e.key !== 'Tab') return;
const items = focusableRef.current;
if (items.length === 0) return;
const first = items[0];
const last = items[items.length - 1];
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
};
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
}, [isOpen]); // onClose 제거
// ... 나머지 코드
}| </div> | ||
| <div className={styles.content}> | ||
| {teamSelect && (typeof teamSelect === 'function' ? teamSelect(isCollapsed) : teamSelect)} | ||
| {typeof children === 'function' ? children(isCollapsed) : children} |
There was a problem hiding this comment.
가독성과 유지보수성 향상을 위해 다른 슬롯 prop들(teamSelect, addButton)과 일관된 렌더링 패턴을 사용하는 것이 좋습니다. children prop을 렌더링하기 전에 존재 여부를 확인하는 로직을 추가하는 것을 제안합니다.
| {typeof children === 'function' ? children(isCollapsed) : children} | |
| {children && (typeof children === 'function' ? children(isCollapsed) : children)} |
Summary
사이드바 컴포넌트 입니다.
Issue
Closes #
특이사항
모바일 버전 로고 추가하였습니다.