fix ui issue - boostcampwm-2022/web33-Mildo GitHub Wiki
UI ์ด์ ํด๊ฒฐ (#68, https://github.com/boostcampwm-2022/web33-Mildo/issues/86)
์์ธ๋ชจ๋ฌ์ฐฝ ์ ๋ชฉ ์ ๋๋ฉ์ด์ ๋ณ๊ฒฝ (v)
๊ฒ์์ฐฝ ํฌ์ปค์ค ์ ์์๋ผ์ธ ํด์
๋ก๊ทธ์ธ ๋ชจ๋ฌ์ฐฝ, ์ฌ์ด๋๋ฐ ๋ชจ๋ฌ์ฐฝ ์ ๋๋ฉ์ด์ ์ ์ฉ
๊ฒ์ ์๋์์ฑ ๋ชจ๋ฌ ๋๋น ๊ธธ์ด ์กฐ์
export const Title = styled.h1`
...
/* width: 100%; */
...
`;
- width: 100% ์ ๊ฑฐ โ ์ด๊ฑธ๋ก ์ธํด offsetWidth, clientWidth, scrollWidth์ด ๋ชจ๋ ๊ฐ์ px์ด ๋์ค๊ธฐ ๋๋ฌธ์ ์ ๋ชฉ์ width๋ฅผ ์ ํํ๊ฒ ์ธก์ ํ ์ ์๊ฒ ๋๋ค.
const titleWidthRef = useRef<HTMLHeadingElement>(null);
...
useEffect(() => {
if (titleWidthRef && titleWidthRef.current) {
setTitleWidth(titleWidthRef.current.clientWidth);
}
}, [firstLevelInfo]);
- titleWidthRef ์์ฑ์ Title ์๋ฆฌ๋จผํธ์ ์ค์ ํ์ฌ, ํด๋น ์๋ฆฌ๋จผํธ์ ๋์ํ๋ width๋ฅผ ๊ตฌํ ์ ์๋๋ก ํ๋ค.
- ์๋๋ useLayoutEffect๋ก ๊ตฌํํ๊ณ ์ ํ๋ค. useLayoutEffect๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ค๋ฉด ํ๋ฉด ๊น๋นก์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค๋ ์ฅ์ ๊ณผ, ๋ ๋๋ง ์์ ์์ ๋๊ธฐ์ ์ผ๋ก ์คํ๋๊ธฐ ๋๋ฌธ์ ์๋๊ฐ ๋๋ ค์ง๋ค๋ ๋จ์ ์ ์๊ณ ์๋ค. ์๋์ ๋๋ฆผ ํ์์ ์ ์๋ฏธํ๊ฒ ์ฒด๊ฐํ์ง๋ ์์๊ธฐ ๋๋ฌธ์ ์ผ๋จ์ useEffect๋ฅผ ์ฌ์ฉํด์ ๊ตฌํํ๋ค. (์ฐธ๊ณ ์๋ฃ: https://guiyomi.tistory.com/120)
const [windowWidth, setWindowWidth] = useState<number>(window.innerWidth);
useEffect(() => {
const checkViewportWidth = () => {
setWindowWidth(window.innerWidth);
};
window.addEventListener('resize', checkViewportWidth);
// ํด๋ฆฐ์
ํจ์
return () => {
window.removeEventListener('resize', checkViewportWidth);
};
}, []);
- ๊ทธ ๋ค์์ผ๋ก๋, ๋ทฐํฌํธ(ํ๋ฉด ์ ์ฒด)์ ๋๋น๋ฅผ ๊ตฌํ๊ธฐ ์ํ ์ฝ๋๋ฅผ ์์ฑํ๋ค. window.innerWidth๋ก ์ด๊ธฐํ๋ฅผ ์งํํ๋ค.
- ํด๋ฆฐ์ ํจ์๋ฅผ ๋ฃ์๋ค. ์ด ํจ์๋ ์ฌ๋ ๋๋ง์ด ๋๋ ์์ ๊ณผ ์๋ก์ด useEffect ํจ์๊ฐ ํธ์ถ๋๋ ์์ ์ฌ์ด์ ์คํ๋๋ค. ๋ฐ๋ผ์ โresize'์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๊ฒ ๋๋ฉด checkViewportWidth โ setWindowWidth๋ฅผ ํตํด ์๋ก์ด window.innerWidth์ผ๋ก ๊ฐ์ ๊ฐฑ์ ์์ผ ์ฃผ๊ณ , ์ฌ๋ ๋๋ง ๋๋ค.
- โํด๋ฆฐ์ ํจ์โ๋ฅผ ํตํด ์ปดํฌ๋ํธ๊ฐ ์ธ๋ง์ดํธ๋๋ ๊ฒฝ์ฐ์๋ ์ด๋ฒคํธ ๋ฆฌ์ค๋๊ฐ ์คํ๋์ง ์๋๋ก ์ค์ ํ๋ค.
const [slidable, setSlidable] = useState<boolean>(true);
...
useEffect(() => {
if (titleWidth + 50 > windowWidth) {
setSlidable(true);
return;
}
setSlidable(false);
}, [titleWidth, windowWidth]);
- ์ด์ titleWidth, windowWidth๋ฅผ ์ ๋ถ ๊ฑธ์ด์ฃผ์๊ธฐ ๋๋ฌธ์, ๊ทธ ๋ค์์๋ slidable์์ฑ์ ๊ฑธ์ด์ฃผ์ด์ผ ํ๋ค. titleWidth, windowWidth์ ์ํ๊ฐ์ด ๋ณํํ ๋๋ง๋ค ๋ฐ๋ ์ ์๋๋ก ์ค์ ํ์์ผ๋ฉฐ, ๋ง์ฝ์ ์ ๋ชฉ์ด ๋๋ฌด ๊ธธ๋ค๊ณ ํ๋จ๋๋ ๊ฒฝ์ฐ์๋ ์ ๋๋ฉ์ด์ ํจ๊ณผ๋ฅผ ๊ฑธ์ด๋๊ณ , ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ์๋ ์ ๋๋ฉ์ด์ ํจ๊ณผ๋ฅผ ๊ฑธ์ง ์๋๋ก, **setSlidable()**์ ํตํด์ ๊ฐ์ ์ค์ ํ๋ค.
<Title ref={titleWidthRef} slide={slidable} textWidth={titleWidth}>
ํ์ฌ
<TitleLocation
populationLevel={firstLevelInfo[1].populationLevel}>
{firstLevelInfo[0]}
</TitleLocation>
{INFO_DETAIL_TITLE[firstLevelInfo[1].populationLevel]}
</Title>
{slidable ? (
<Title
ref={titleWidthRef}
slide={slidable}
textWidth={titleWidth}>
ํ์ฌ
<TitleLocation
populationLevel={firstLevelInfo[1].populationLevel}>
{firstLevelInfo[0]}
</TitleLocation>
{INFO_DETAIL_TITLE[firstLevelInfo[1].populationLevel]}
</Title>
) : (
<></>
)}
export const Title = styled.h1<TitleTypes>`
display: block;
text-align: center;
font-size: 1rem;
white-space: nowrap;
will-change: transform;
animation: ${props =>
props.slide
? css`
${marquee(props.textWidth)} 10s linear infinite
`
: ''};
`;
- ์ด์ slidable ์ํ๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก Title์์ slide props๋ก ๋๊ฒจ์ฃผ๊ณ , styled-component์์ slide์ ๊ฐ์ ๋ฐ๋ผ ์ ๋๋ฉ์ด์ ๊ตฌํ ์ฌ๋ถ๋ฅผ ์ค์ ํ๋ค.
- textWidth props๋ฅผ ํตํด marquee ์์ฑ์ ์ ์ฉํ ๋, ํด๋น ํ ์คํธ ๊ธธ์ด์ ๋ง๋ ๊ฐ์ ๋ฃ์ด์ค๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ํ ์คํธ ๊ธธ์ด ์ฌ๋ถ์ ์๊ด์์ด ๋ชจ๋๊ฐ ๋์ผํ ์์น์์ ๋์ผํ ์๋๋ก ์ด๋ํ๊ฒ ๋๋ค.
- ๊ฒฐ๋ก : keyframes์ transform: translate() ์์ฑ์ x๊ฐ์ ํด๋น ํ ์คํธ ๊ธธ์ด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ค์ ํ๊ณ , flexbox์ gap ์์ฑ์ 50%๋ก ์ค์ , ๋ง์ง๋ง์ผ๋ก ๋ ๊ฐ์ Title ์๋ฆฌ๋จผํธ๋ฅผ ๋ ๋๋ง ์์ผ์ฃผ๋ฉด ๊ฐ์ฅ ์ต์ ํ๋ ์ ๋๋ฉ์ด์ ์ด ์์ฑ๋๋ ๊ฒ ๊ฐ๋ค.
&:focus {
outline: none;
}
- ํด๋น ์๋ฆฌ๋จผํธ์ focus ์ด๋ฒคํธ ์ ์ฉํ ์
outline: none
์ ์ ์ฉํ์ฌ ๊ฐ๋จํ๊ฒ ํด๊ฒฐ.
- ๋ก๊ทธ์ธ ๋ชจ๋ฌ๊ณผ ์ฌ์ด๋๋ฐ์ ๋ชจ๋ฌ ์ ๋๋ฉ์ด์ ์ ๋ค๋ฅด๊ฒ ์ ์ฉํ๋ ค๊ณ ํ์ง๋ง, ๊ฐ๊ฐ ๋ฐ๋ก ์ ๋๋ฉ์ด์ ์ ์ ์ฉํ๋ ์ผ์ด ์๊ฐ๋ณด๋ค ๊ฝค ๊ท์ฐฎ์ ์ผ์ด๊ธฐ ๋๋ฌธ์ ํ๋์ ์ ๋๋ฉ์ด์ ์ผ๋ก ๋์ผํ๊ฒ ์ ์ฉํ๊ณ ์ ํ๋ค.
return (
<>
{/* {isOpen && (
<>
{background && <Filter onClick={clickModalHandler} />}
<ModalContainer customModalStyle={customModalStyle}>
{children}
</ModalContainer>
</>
)} */}
<Filter onClick={clickModalHandler} open={isOpen && background} />
<ModalContainer customModalStyle={customModalStyle} open={isOpen}>
{children}
</ModalContainer>
</>
);
};
- ์ผ๋จ ์ผํญ์ฐ์ฐ์๋ฅผ ๊ฑท์ด๋๋ค. ํนํ, ๋ฌด์ธ๊ฐ๋ฅผ ๋ณด์ฌ์ฃผ๋ ค๊ณ ์ ๋๋ฉ์ด์ ์ ๊ฑฐ๋ ๊ฒฝ์ฐ์๋ display: none์ ๊ฑธ๊ฑฐ๋ ์ผํญ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ค๋ฉด ๋์ค์ display ์์ฑ์ ๊ฑธ์ด์ค ์๊ฐ ์๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ ๋์ ์, Filter ์ปดํฌ๋ํธ์ ModalContainer์ open prop์ ์ถ๊ฐํด์, ํด๋น prop์ boolean ์ /๋ฌด์ ๋ฐ๋ผ ์ ๋๋ฉ์ด์ ์ ์ด๋ป๊ฒ ์ ์ฉํ ๊ฒ์ธ ์ง์ ๋ํด์ ์์ฑํ ์์ ์ด์๋ค.
const ModalContainer = styled.div<ModalContainerProps>`
z-index: ${Z_INDEX.MODAL};
${props => props.customModalStyle && props.customModalStyle}
/* display: ${props => !props.open && 'none'}; */
visibility: ${props => (props.open ? 'visible' : 'hidden')};
${props => !props.open && `z-index: -100`};
animation: ${props =>
props.open
? css`
${fadeIn} .2s linear
`
: css`
${fadeOut} .2s linear
`};
`;
const Filter = styled.div<{ open: boolean }>`
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: ${Z_INDEX.FILTER};
background-color: rgba(0, 0, 0, 0.5);
/* display: ${props => (props.open ? 'block' : 'none')}; */
visibility: ${props => (props.open ? 'visible' : 'hidden')};
${props => !props.open && `z-index: -100`};
animation: ${props =>
props.open
? css`
${fadeIn} .2s linear
`
: css`
${fadeOut} .2s linear
`};
`;
- ๊ทธ ๋ค์์ผ๋ก๋
display: none
์์ฑ์ ์ญ์ ํ๋ค. ํด๋น ์์ฑ์ ์ ์ฉํ๊ฒ ๋๋ฉด ์ ๋๋ฉ์ด์ ์ด ์ ๋๋ก ์ ์ฉ๋์ง ์์ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ ๋์ ์,visibility
์์ฑ๊ณผz-index
์์ฑ์ ์ ์ฉํด์ ์๋ณด์ด๊ฒ๋ ์ฒ๋ฆฌ๋ฅผ ์งํํ ๋ค์, ์ ๋๋ฉ์ด์ ์ด ์งํ๋จ์ ์ฌ๋ถ์ ๋ฐ๋ผ์ ๋ณํ๋ฅผ ์ฃผ๊ธฐ๋ก ์๊ฐํ๋ค. - ์ ๋๋ฉ์ด์
์
@keyframes
๋ฅผ ์ ์ฉํ๊ณ ์ ๋ ธ๋ ฅํ์๊ณ , open prop์ boolean ์์ฑ ์ฌ๋ถ์ ๋ฐ๋ผ fadeIn ์ ๋๋ฉ์ด์ ์ ๋ถ์ฌํ ์ง, fadeOut ์ ๋๋ฉ์ด์ ์ ๋ถ์ฌํ ์ง์ ๋ํ ์ฌ๋ถ๋ฅผ ํ๋จํ ์ ์๋๋ก ํ๋ค.
const fadeIn = keyframes`
0% {
opacity: 0;
display: block;
}
100% {
opacity: 1;
}
`;
const fadeOut = keyframes`
0% {
opacity: 1;
display: block;
}
100% {
opacity: 0;
}
`;
- ๋ง์ง๋ง์ผ๋ก fadeIn ์ต์
๊ณผ fadeOut ์ต์
์ ์ดํด๋ณด๋ฉด, ๋ค์๊ณผ ๊ฐ์ด
@keyframes
๋ฅผ ์ ์ฉํด์ ๋ํ๋ด๊ธฐ๋ก ํ๋ค.
์ด ๋ถ๋ถ์ ๋ํ ๊ธฐ๋ฅ ๊ตฌํ์ โ์์ธ๋ชจ๋ฌ์ฐฝ ์ ๋ชฉ ์ ๋๋ฉ์ด์ ๋ณ๊ฒฝโ๊ณผ ํก์ฌํ๊ฒ **useRef()**๋ฅผ ์ฌ์ฉํด์ ๊ตฌํํ์๋ค.
...
const searchBarWidthRef = useRef<HTMLInputElement>(null);
const [searchBarWidth, setSearchBarWidth] = useState(0);
...
useEffect(() => {
const checkSearchBarWidth = () => {
if (searchBarWidthRef && searchBarWidthRef.current!.clientWidth <= 439) {
setSearchBarWidth(searchBarWidthRef.current!.clientWidth);
}
};
window.addEventListener('resize', checkSearchBarWidth);
return () => {
window.removeEventListener('resize', checkSearchBarWidth);
};
}, []);
...
return (
<FlexBoxStyle>
<SearchBar
placeholder='๊ฒ์'
onChange={onChangeSearchBar}
value={searchAreaName}
ref={searchBarWidthRef}
/>
<MyButton
onClick={onClickMyButton}
dangerouslySetInnerHTML={{
__html: createMyButtonSvg()
}}></MyButton>
<RelatedAreaList
searchAreaName={searchAreaName}
relatedAreaInfo={relatedAreaInfo}
widthValue={searchBarWidth}
/>
</FlexBoxStyle>
);
- searchBarWidthRef๋ฅผ ๊ตฌํํ์๋ค. ์ด ref๋ SearchBar ๋ด๋ถ์์ ์ฌ์ฉ๋์ด์ง๋ ref๋ก, ๋๋น๋ฅผ ์ธก์ ํ๊ธฐ ์ํด์ ๋ง๋ค์๋ค. ์ด ref ๊ฐ์ SearchBar์ ref๋ก ๋ฑ๋กํ๊ฒ ๋๋ฉด, searchBarWidthRef๋ฅผ ์ฌ์ฉํด์ ๊ฐ์ ๊ตฌํ ์ ์๋ค.
- **useEffect()**๋ฅผ ์ฌ์ฉํด์ ์ด์ ๊ณผ ๋น์ทํ๊ฒ ์ด๋ฅผ ๊ตฌํํ์๋ค. window.addEventListener๋ฅผ ์ด์ฉํด์ โresizeโ ์ด๋ฒคํธ๋ฅผ ๊ฑธ๋ฉด, checkSearchBarWidth ํจ์๊ฐ ์คํ๋๋ค. ๊ฒ์๋ฐ์ ์ต๋๊ฐ์ด 439ํฝ์ ์ด๊ธฐ ๋๋ฌธ์ ์ด ๋ฒ์ ๋ด์ ์๋ ๊ฒฝ์ฐ์๋ง setSearchBarWidth() ํจ์๋ฅผ ์คํ์ํค๊ณ ์ํ๊ฐ์ ๋ฐ๊พผ๋ค. ์ด ๋, ๊ฐ์ ๋ฐ๊พธ๋ ๊ธฐ์ค์ ๋ฐ๋ก 'refโ๋ฅผ ๊ฑด ๋์์ width ๊ฐ์ด๋ค.
- RelatedAreaList ์๋ฆฌ๋จผํธ์ widthValue ์์ฑ๊ฐ์ ๋ด๋ ค์ค๋ค. searchBarWidth๋ setSearchBarWidth() ํจ์๋ก ์ธํ์ฌ ๋ฐ๋์ด์ง๋ ๊ฐ์ด๋ค.
...
const RelatedAreaListStyle = styled.ul<{ width: number }>`
width: ${props => props.width}px;
max-width: 439px;
max-height: 15rem;
overflow: auto;
display: flex;
flex-direction: column;
justify-content: space-between;
position: absolute;
top: 3.5rem;
background-color: white;
border-radius: 10px;
border: none;
box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.25);
list-style: none;
`;
...
return (
<>
{isRelatedAreaListOpen && (
<RelatedAreaListStyle
onClick={onClickRelatedAreaList}
width={widthValue}>
{isEmptyRelatedList ? (
<RelatedAreaItem
searchAreaName={searchAreaName}
areaInfo={emptyAreaInfo}
/>
) : (
- RelatedAreaListStyle ์๋ฆฌ๋จผํธ์์ ๋ฐ์์จ widthValue๋ฅผ width๋ก ๋ด์ฌ์ฃผ๋ฉด, styled-components์์ width ๊ฐ์ ๊ฒ์์ฐฝ ๋ฐ์ ๋์ผํ๊ฒ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค.
- ํ์ฌ **์์ธ๋ชจ๋ฌ(1๋จ๊ณ)**์์ ๋ณด์ฌ์ฃผ๊ณ ์๋ ์ ๋ชฉ ๊ด๋ จ ๋ถ๋ถ์ด ํ๋ฉด์ด ์์ ๋ชจ๋ฐ์ผ์์๋ ์๋ ค์ ธ์ ๋์ค๊ธฐ ๋๋ฌธ์, ์ด๋ฅผ ์ ๋๋ฉ์ด์ ํํด์ ๋ณด์ฌ์ฃผ์ด์ผ ํฉ๋๋ค. ์ด๋ค ๋ฐฉ์์ผ๋ก ์ ๋๋ฉ์ด์ ํ๋ฅผ ์งํํ๋ฉด ์ข์ ์ง ์ฐพ๋ ์ค์ ๋ค์์ ๋งํฌ๋ฅผ ํตํด margin-left, margin-right ์์ฑ์ ๋ถ์ฌํด์ ๋ณด์ฌ์ฃผ๋ฉด ๋ ๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ด ๋ค์๋ค.
-
animation: 12s autoplay3 infinite linear
- infinite: ์ ๋๋ฉ์ด์ ์ ๋ฌดํํ ๋ฐ๋ณตํ ์ ์๋๋ก ์ค์ ํ๋ค.
- linear: ์ ํ์ ์ผ๋ก ์์ง์ผ ์ ์๊ฒ๋ ์ค์ ํ๋ค. linear ์์ฑ์ ์ ์ฉํ๋ฉด ํญ์ ์ผ์ ํ๊ฒ ์์ง์ผ ์ ์๊ฒ ๋๋ค.
-
offsetWidth, clientWidth, scrollWidth
- ์ผ๋จ, **vw(viewport-width)**์ ํ์ฌ ์ ๋ชฉ์ width ์์ฑ์ ๋์์ ๊ตฌํ ๋ค์, ์ด๋ค ๊ฐ์ ๊ธธ์ด๋ฅผ ๋น๊ตํด์ ๊ฒฝ์ฐ์ ๋ฐ๋ผ ๋ค๋ฅธ ํจ๊ณผ๋ฅผ ์ ์ฉํด์ผ ํ๋ค. ๋ง์ฝ์ vw๊ฐ ๋ ํฐ ๊ฒฝ์ฐ์๋ ๊ตณ์ด overflow๊ฐ ๋ฐ์ํ์ง ์๊ธฐ ๋๋ฌธ์ ์ ๋๋ฉ์ด์ ์ ๊ตฌํํ์ง ์์๋ ๋๋ค. ๊ทธ๋ฌ๋, ๋ง์ฝ์ ์ ๋ชฉ์ width๊ฐ ๋ ํฐ ๊ฒฝ์ฐ์๋ ์ ๋ชฉ์ด ์๋ ค์ ๋ณด์ฌ์ง๊ธฐ ๋๋ฌธ์ ์ ๋๋ฉ์ด์ ํจ๊ณผ๋ฅผ ๊ตฌํํด์ผ ํ๋ค.
- ์ด ์ธ๊ฐ์ง width ์์ฑ์ด ๋ชจ๋ ๋ค๋ฅด๊ณ , ์ด๋ค ์ค์ ์ด๋ค width ์์ฑ์ ์ ์ฉํด์ผ ํ ์ง ๊ณ ๋ฏผ๋์๋ค.
- ์ผ๋ฐ์ ์ผ๋ก ์๋ฆฌ๋จผํธ์ ์ ์ฒด ํฌ๊ธฐ๋ฅผ ์๊ณ ์ถ๋ค๋ฉด,
offsetWidth
์offsetHeight
์์ฑ - ์ค์ ๋ก ๋ณด์ฌ์ง๊ณ ์๋ ์ปจํ
์ธ ๊ฐ ์ผ๋ง๋งํผ์ ๊ณต๊ฐ์ ์ฐจ์งํ๊ณ ์๋์ง ํ์ธํ๊ณ ์ถ๋ค๋ฉด,
clientWidth
์clientHeight
์์ฑ - ๋ณด์ด๋ ๊ฒ๊ณผ ์๊ด ์์ด ์ค์ ์ปจํ
์ธ ์์ญ์ด ์ผ๋ง๋งํผ์ ํฌ๊ธฐ๋ฅผ ๊ฐ๊ณ ์๋์ง ํ์ธํ๊ณ ์ถ๋ค๋ฉด,
scrollWidth
์scrollHeight
์์ฑ
- ์ผ๋ฐ์ ์ผ๋ก ์๋ฆฌ๋จผํธ์ ์ ์ฒด ํฌ๊ธฐ๋ฅผ ์๊ณ ์ถ๋ค๋ฉด,
-
useLayoutEffect
- useEffect์ ์ฌ๋ฌ ๋ชจ๋ก ๋น์ทํด ๋ณด์ด์ง๋ง, ๋ ๊ฐ์ ์ฐจ์ด๋ ๋ถ๋ช
ํ ์กด์ฌํ๋ค.
- useEffect๋ ๋ ๋๋ง์ ์งํํ๊ณ ํ์ธํธ๋ ์ดํ์ ์คํ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ์์ ์ด ๋น๋๊ธฐ์ ์ผ๋ก ์คํ๋๋ค๋ ํน์ง์ ๊ฐ์ง๊ณ ์๋ค. ๊ทธ๋ฌ๋, useLayoutEffect๋ ๋ ๋๋ง๊ณผ ํ์ธํ ์ฌ์ด์ ์คํ๋๋ฉฐ ์ด ์์ ์ ๋๊ธฐ์ ์ผ๋ก ์คํ๋๋ค๋ ํน์ง์ ๊ฐ์ง๊ณ ์๋ค.
- useEffect์ ์ฌ๋ฌ ๋ชจ๋ก ๋น์ทํด ๋ณด์ด์ง๋ง, ๋ ๊ฐ์ ์ฐจ์ด๋ ๋ถ๋ช
ํ ์กด์ฌํ๋ค.