묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결[React / VanillaJS] UI 요소 직접 만들기 Part 2
스낵바를 만들 때 snackBarContext와 snackBarSetContext
스낵바를 만들 때 snackBarContext와 snackBarSetContext를 둘로 나누셔서 관리하는데 이렇게 하신 이유나 장점을 정확히 알 수 있을까요?단점도 알려주시면 감사드리겠습니다.
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 1
무한스크롤 리액트버전 | 16분 31초
16분 31초에 const useInfiniteFetcher =() => {} 여기 부분을 보게 되면pageData는 async에서 받아와서 promise가 되었는데강사님은 따로 .then을 안하셨는데 어떻게 가능한가요??
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 2
snackbar를 createportal를 썻을 때 갯수 조절이 가능한가요?
context를 썻을때는 data length로 체크하면 최대 5개가 넘지 않게 더이상 오픈되지 않거나 가장 밑에 스낵바를 닫아 버린다던가 쉽게 구현을 가능할 것 같은데 portal를 쓰면 컨트롤이 가능한가? 궁금합니다
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 1
강의자료 github link 404 빈페이지
빈페이지로 나오는데 왜그런걸까요?https://github.com/fe-ui-study/ui-study
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 2
useCallback, useMemo의 차이에 대해서 궁금합니다.
[셀렉트박스 (3/5) headless #2 hook 적용] 부분에서 getTriggerProps/getListProps 처럼 각 컴포넌트가 필요한 것들을 useCallback으로 감싸고 함수형태로 제공해주셨는데요, 아래처럼 useMemo를 이용해서 객체에 값을 담아서 전달해주는 방식은 다른 걸까요??const getTriggerProps = useCallback( () => ({ selectedItem: items[selectedIndex], toggle, }), [selectedIndex, items, toggle] ); const TriggerpropsValue = useMemo(() => { return { selectedItem: items[selectedIndex], toggle, }; }, [items, selectedIndex, toggle]);
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 2
createPortal 활용해서 modal 만들 때 활용한 MutationObserver 코드 관련 질문
import { useEffect, useRef } from "react" const mutationObserverOption: MutationObserverInit = { childList: true, subtree: true } const ModalRoot = () => { const ref = useRef<HTMLDivElement>(null); useEffect(() => { let observer: MutationObserver if (ref.current) { observer = new MutationObserver(() => { const size = ref.current?.childNodes.length || 0 document.body.classList.toggle('no-scroll', size > 0) }) observer.observe(ref.current, mutationObserverOption) } return () => { observer.disconnect() } }, []) return (<div id="modalRoot" ref={ref}/>) } export default ModalRoot; 수업시간에 구현 되었던 코드가 어떤 순서로 동작하는지 콘솔로 확인해봤습니다. 제가 확인해 봤을 땐 처음 페이지가 렌더링 될 때 1. ModalRoot 컴포넌트가 실행 2. modalRoot div가 생성 3. useEffect가 실행4. useEffect의 Clean Up 작동까지는 예상대로 진행되었습니다. 하지만 이후에 이해가 안되는 부분이 있습니다.질문 1) 이후 useEffect가 다시 실행되는데, 의존성도 없는데 어떻게 다시 실행되는지 궁금합니다.질문 2) 영상에서 모달 버튼을 누르면 useEffect의 조건문에서 size를 콘솔로 확인하셨는데, ModalRoot 컴포넌트가 재실행되지 않고 어떻게 size를 확인할 수 있는지 궁금합니다.
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 2
강의자료 (보일러플레이트) 다운로드 관련 질문
강의 커리큘럼을 보면 "강의자료 (완성본)"과 "강의자료 (보일러플레이트)" 다운로드를 구분해 두셨는데, 다운로드는 "강의자료 (완성본)"만 만 받게 되어 있는거 같습니다.혹시 보일러플레이트 강의자료는 아직 준비가 되지 않은것일까요?완성본 README.md에 있는 `git clone https://github.com/fe-ui-study/ui-study.git`도 Repository를 찾지 못하고 있습니다.
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 1
아코디언 (3/6) css transition 추가 부분 max-height 질문
안녕하세요, 수강 중에 css transition 파트에서 궁금증이 생겨 질문 드립니다. max-height 속성을 이용해서 애니메이션을 적용해주셨는데, 아래 방식처럼 height를 0, auto로 애니메이션 주는 것과 차이가 있을까요? .item3 { overflow: hidden; .description { padding: 0 15px; border-bottom-width: 0; // max-height: 0; height: 0; transition: ease 0.3s; } &.current .description { padding: 15px; border-bottom-width: 1px; // max-height: 300px; height: auto; } }
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 1
강의 정리에 대한 블로그 정리 글 게시 문의
안녕하세요 강의를 들으면서 정리하는 데 블로그에 게시글로 같이 올려도 가능한지 문의드립니다 예를 들어 아코디언을 듣고 코드와 주석 및 정리한 내용들을 바탕으로 출처와 함께 글을 올리는 것입니다 따로 강의 코드에 대한 github이 없는 것 같아 여쭤봅니다 !
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 2
모달만드는 방식 질문
안녕하세요 재남님 강의 너무 잘듣고 있습니다이번 강의 듣고 생각이 드는게 저는 지금까지 모달을 만들때 각각의 모달을 완성본으로 만들고 모달을 부르는 트리거버튼이나 그,런것에 상태를 주고 상태의 변경에따라 그 아래에 그리는 방식으로 모달을 구현했습니다이번강의도 보면 비슷하긴한데 모달을 만드는곳에서 모든것을 만드는것이 아니라 모달이라는(컴파운드 패턴..? 사실 이건 처음봐서 혼란스럽네요...ㅎㅎ)컴포넌트에서 기본 적인 css와 칠드런등을 만들어놓고 모달에서는 이것들을 가져와서 완성본 모달을 만드는것으로 이해를 했습니다 제가 궁금한것은실무에서는 보통 이렇게 만드는지 궁금합니다이렇게 만드는것의 장점이 있을까요?(찾아보니 재사용성이 좋다고 하는데 이부분이 크게 와닿지가 않네요..)
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 2
캐러셀 동작원리
안녕하세요 재남님 강의 너무 잘듣고 있습니다제가 지금 캐러셀 공부하면서 궁금한것이캐러셀 각 이미지에 ref를 다 할당한다슬라이드 이벤트 화살표 클릭시 이동할 인덱스를 계산하고 인덱스를 기준으로 current와 next의 ref를 가져온다그럼 가져온 ref에 각각 애니메이션 클래스네임을 할당한다 애니메이션에 따라 translateX만큼 이동 , 마지막으로 이동한 인덱스 상태변화 이렇게 동작원리를 이해를 하였습니다 그래서 일단 animationend는 없어도 될거 같아서 일단 없애고 코드를 작성하니 화면 전환은 되는데 자연스러운 슬라이드가 아니라 그냥 뚝뚝끊기는 이미지 전환이 되고있습니다.. 제 생각엔 handleAnimationEnd함수는 애니메이션 동작완료후 동작하는것이라고 알고있는데 애니메이션이 동작을 안하는 이유를 모르겠습니다 const moveTo = useCallback( (nextIndex: number, direction?: Direction) => { const $current = itemsRef.current![currentIndex] as HTMLLIElement; const $next = itemsRef.current![nextIndex] as HTMLLIElement; if (nextIndex === currentIndex) return; const dir = direction || (nextIndex > currentIndex ? "right" : "left"); // const handleAnimationEnd = () => { // $current.className = cx("item"); // $next.className = cx("item", "current"); // $current.removeEventListener("animationend", handleAnimationEnd); // setCurrentIndex(nextIndex); // }; // $current.addEventListener("animationend", handleAnimationEnd); $current.classList.add(cx(`${dir}_current`)); $next.classList.add(cx(`${dir}_next`)); setCurrentIndex(nextIndex); }, [currentIndex] );
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 1
[아코디언 1/6 챕터] 클로저 활용 질문 있습니다.
안녕하세요! 이제 막 강의를 듣고 있는 배정규라고 합니다. 아코디언 강의를 듣고나니 UI 컴포넌트 개발뿐만 아니라 자바스크립트와 프론트엔드 개발의 실무 팁까지 배울 수 있겠다라는 기대감이 생기네요 🙂 질문은 toggleItem 함수를 클로저를 활용해서 개선을 해주셨는데요, 왜 클로저로 개선을 해주셨는지가 궁금합니다. 클로저를 활용했을 때와 이전 함수와 비교했을 때 어떤 이점이 생기는지 크게 와닿지가 않아서요.왜 toggleItem 함수를 클로저를 활용해서 개선해주셨는지 궁금합니다 😃
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 2
dropdown 내부에서 data의 타입을 알아야 할까요?
앞선 질문들에서 친절하게 답변주셔서 감사합니다! 항상 많이 배우고 있습니다 <Dropdown.Provider> <Dropdown.Container> <DropDown.Trigger> <Dropdown.List> {data.map((item) => ( <Dropdown.Item key={item.key} /> )} </Dropdown.List> </Dropdown.Container> </Dropdown.provider>가독성이 조금 떨어지지만 createDropdown을 만들지 않아도 되고, 제네릭으로 타입을 복잡하게 주지 않아서 이 방법도 괜찮을 것 같은데 어떨까요?!
-
미해결시나브로 자바스크립트
번들러를 꼭 사용해야하나요?
안녕하세요!저는 리액트 컴포넌트 라이브러리를 도전해보고 있습니다. 대부분은 Rollup, Microbundle 등의 번들러를 활용한다는 것을 알게 되었습니다. 그런데 조사해보니 굳이 번들러 없이도 컴포넌트 라이브러리를 만들 수 있다는 것을 알게 되었습니다.tsc 컴파일을 통해 TypeScript 환경과 JavaScript 환경 둘 다 지원하는 라이브러리를 만들었고, 샘플 프로젝트에서 설치해본 결과 잘 작동합니다.이런 상황에서 번들러가 왜 필요한지 잘 모르겠습니다.번들러의 역할에 대해서는 알고 있습니다. 폴리필을 제공하기도 하고, 하나의 자바스크립트 파일로 만들어서 네트워크 요청 횟수를 줄여주기도 하지요.하지만, 이 번들러를 컴포넌트 라이브러리에 꼭 사용해야 하는지 궁금합니다. 제가 만든 이 컴포넌트 라이브러리를 배포하고, 한 샘플 프로젝트에서 이 라이브러리를 npm install 했다고 가정해보겠습니다. 이 프로젝트는 Vite를 번들러로 사용하고 있습니다. 결국 배포할 때 번들링을 하게 될 텐데, 그러면 컴포넌트 라이브러리도 자동으로 함께 번들링에 포함되지 않나요? 어차피 프로젝트에서 번들링 될 건데, 미리 번들링할 필요가 있을까요?
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 2
Provider를 외부에 노출하는 것보다 내부 로직으로 숨기는 것은 어떤가요?
<Dropdown.Provider list={data}> <Dropdown.Container> <Dropdown.Trigger></Dropdown.Trigger> <Dropdown.List></Dropdown.List> </Dropdown.Container> </Dropdown.Provider>위와같이 Provider을 노출하는 것보다, 아래와 같이 Container 내부에 Provider을 불러와서 사용하는 것이 캡슐화 측면에서 좋지 않나요?! // DropdownContainer <DropdownContextProvider> <div className={cx("Dropdown")} onKeyDown={handleKeyDown} onClick={(e) => e.stopPropagation()} > {children} </div> </DropdownContextProvider> <Dropdown.Container list={data}> <Dropdown.Trigger></Dropdown.Trigger> <Dropdown.List></Dropdown.List></Dropdown.Container>
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 2
keyEventMap를 전역에 구현하신 이유가 궁금합니다!
const KeyEventMap: Partial<Record<KeyboardEvent<Element>['key'], KeyEventHandler>> = { ArrowUp: (e, { size, focusIndex }) => { e.preventDefault() focusIndex(prev => (size + prev - 1) % size) }, ArrowDown: (e, { size, focusIndex }) => { e.preventDefault() focusIndex(prev => (size + prev + 1) % size) }, Enter: (e, { focusedIndex, selectIndex }) => { e.preventDefault() selectIndex(focusedIndex) }, Escape: (e, { toggle }) => { toggle(false) }, } 제 짧은 지식으로는 focusIndex, selectIndex를 파라미터로 받는 것보다 context 내부에서 그냥 사용하는 것이 더 간단할 것 같다고 생각했습니다. keyEventMap을 전역에 구현하여, focusIndex와, selectIndex를 따로 파라미터로 받아서 사용하시는 이유가 있을까요?
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 1
item7 style이 강의자료에 없습니다.
아코디언 8_r.tsx에서 item7 클래스를 주셨는데 강의자료에 item7 클래스가 없는 것 같아요!
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 1
이벤트 핸들러가 Root에 모이면
리액트에서는 onClick으로 이벤트를 등록하면 Root에 모이게 된다고 하셨는데제가 이 부분을 정확히 이해했는지 알고싶어서 질문 드립니다!보통은 자바스크립트에서는 각 요소마다 addEventListener를 여러 번 호출하면 메모리 측면에서 비효율적이고 성능이 떨어질 수 있다고 알고 있습니다. 그래서 이벤트 위임을 사용하는 것으로 이해했습니다. 현재 강의에서는 각 요소마다 onclick 이벤트를 등록하셨는데 리액트에서는 Root에서 중앙통제하기 때문에 상관없다는 것으로 인지했습니다.제가 알기로는 이벤트들을 모아다가 root에 addEventListener를 하는 것으로 알고 있는데 이게 맞을까요?그러면 리액트에서는 굳이 이벤트 위임을 사용할 필요가 없을까요? 예를 들어 onClick을 여러 요소에 등록하지 않고 상위 요소 하나에만 등록하는 것처럼 말이죠..!
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 1
append와 insertAdjacentElement 차이가 무엇일까요?
insertAdjacentElement 를 사용해서 구현하셨는데저 부분을 append로 해도 똑같은 결과가 나옵니다.혹시 append말고 insertAdjacentElement를 사용하신 이유가 있을까요?개인적으로 검색해봤는데 append와 차이점이 insertAdjacentElement는 '지정한 위치에 요소를 삽입할 수 있다'는 점 이외에는 없더라구요..ㅠ어떤 장점때문에 insertAdjacentElement 를 사용한지 알고 싶습니다!
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 2
테일윈드로 포탈로 모달작성시 뒤에 클릭이 안됩니다
<div id='modalRoot' ref={ref} className='fixed inset-0 z-100 flex flex-col items-center justify-center' > {children} </div>테일 윈드로 선생님 모달 포탈로만드는것 해보고있는데.뒤에 클릭이 안되요 pointer-events-none 쓰지말고 하는법이 없을까요?!일단은 아래처럼 쓰고잇긴한데 ㅠㅠ 먼가 ...'use client'; import React, { useEffect, useRef } from 'react'; import { useModalStore } from '@/shared/models/modal/stores/modalStore'; const mutationObserverOption: MutationObserverInit = { childList: true, subtree: false, }; /** * 모달 컴포넌트를 렌더링하기 위한 전역 컨테이너 프로바이더입니다. * 모달이 열려 있을 때 body 요소에 'no-scroll' 클래스를 토글하여 스크롤을 비활성화합니다. * * @param {React.ReactNode} children - 모달 루트 내부에 렌더링할 자식 요소 * @returns {JSX.Element} 모달 루트 프로바이더 */ const ModalRootProvider: React.FC<{ children: React.ReactNode }> = ({ children, }) => { const ref = useRef<HTMLDivElement>(null); const { openedModalTypes, closeModal } = useModalStore(); // const isModalOpen = openedModalTypes.length > 0; useEffect(() => { let observer: MutationObserver; /** * MutationObserver를 사용하여 모달 루트 컨테이너의 자식 요소 변경을 감지합니다. * 모달이 열려 있는 경우 body 요소에 'no-scroll' 클래스를 추가하고, 모달이 닫혀 있는 경우 클래스를 제거합니다. */ if (ref.current) { observer = new MutationObserver(() => { const size = ref.current?.childNodes.length || 0; document.body.classList.toggle('no-scroll', size > 0); ref.current!.classList.toggle('bg-black/50', size > 0); ref.current!.style.pointerEvents = size > 0 ? 'auto' : 'none'; }); observer.observe(ref.current, mutationObserverOption); } // 컴포넌트 언마운트 시 MutationObserver 연결을 해제합니다. return () => { observer.disconnect(); }; }, []); return ( <div id='modalRoot' ref={ref} className='fixed inset-0 z-100 flex flex-col items-center justify-center pointer-events-none' // onClick={handleOutsideClick} > {children} </div> ); }; export default ModalRootProvider;