useLayoutEffect
는 동기적으로
작동하며 render
후에 실행된다.
useEffect
와 다른 부분이 이 부분이다.
useEffect
는 render -> paint -> useEffect
.
useLayoutEffect
는 render -> useLayoutEffect -> paint
.
paint
되기전에 실행되므로 useLayoutEffect
에 의해 상태가 바뀌면 그 다음 단계인 paint
로 가지 않고 render
가 실행되므로 화면이 깜박거림을 방지할 수 있다.
paint
단계는 웹페이지에 컴포넌트를 나타내는 단계이므로 상태가 변경된 컴포넌트에 다시 paint
되어 깜박거림을 일으킨다.
const [value, setValue] = useEffect(0);
useLayoutEffect(() => {
if (value === 0)
setValue(10)
})
위 코드에서 상태 변수value
의 값이 0
이므로 render -> useLayoutEffect
단계에서 setValue(10)
이 호출되어 상태 변경으로 인해 render
가 다시 실행된다. 이 말은 paint
가 되지 않았으므로 다시 render
후에 paint
가 되는 것이므로 화면 깜박거림이 나타나지 않는다.
공부하면서 알게된 것은 useLayoutEffect
를 지양하고 useEffect
를 주로 써야한다는 것이다. 이유는 useLayoutEffect
는 동기적으로
작동하므로 paint
이전에 useLayoutEffect
에서 복잡한 로직이 처리되는 것이라면 유저들은 웹페이지가 바로 화면에 나타나는 것을 보지 못하는 좋지 않은 유저 경험을 하게 되기 때문인듯하다.
synchronous
render
-> useLayoutEffect
-> paint
const inputEl = useRef(null)
const handleClick = () => {
// button이 클릭되면 `input`요소에 focus 두기.
inputEl.current.focus();
}
return(
<input ref={inputEl} type='text'/>
<button onClick={handleClick}>검색</button>
)
.current
프로퍼티를 가진 오브젝트를 리턴event
발생없이 HTML 요소에 접근 가능만약, useRef
가 없다면 event
가 일어날때만 onClick
과 같은 어트리뷰트를 등록하여 event.target
으로 접근해야할 거 같다.
상태 변수
를 글로벌로 설정하면 자식 컴포넌트들을 통해 계속 props
를 던져주면 Props drilling
이슈를 피할 수 있다.
먼저 CardContext 를 생성하기 위한 코드를 작성한다.
// CardContext.tsx
type CardContextProps {
cards: number,
setCards: React.Dispatch<React.SetStateAction<number>>
}
export const CardContext = createContext<CardContextProps | null>(null);
그런 다음, 다른 자식 컴포넌트들을 모두 포함할 App.tsx
에 .Provider
컴포넌트를 추가하여 자식 컴포넌트들을 감싼다. 그러면, 자식 컴포넌트들은 .Provider
컴포넌트의 value
프로퍼티에 담긴 데이터에 접근할 수 있게 된다.
// App.tsx
function App() {
const [cards, setCards] = useState(10);
return (
<CardContext.Provider value={{cards, setCards}}>
<Home />
</CardContext.Provider>
);
}
자식 컴포넌트 중 하나인 Home
컴포넌트에서 이제 cards, setCards
에 접근할 수 있다.
방법은 Home
컴포넌트에서 useContext
를 써서 CardContext
에 접근하면 cards, setCards
에 접근할 수 있다.
// Home.tsx
import CardContext from './CardContext';
function Home() {
const cardContext = useContext(CardContext);
return (
<div>
카드: {cardContext.cards}개
</div>
)
}
cardContext
가 `{cards, setCards}를 받았으므로 Context API를 사용하여 글로벌 상태 변수를 사용하는데 성공했다.
위 방식으로 개발중인 포트폴리오에 적용한