반응형
useLayoutEffect
When?
- DOM에 (직접) 관찰 가능한 변경을 가하여 브라우저가 업데이트된 dom 페인트해야 하는 경우 LayoutEffect를 사용합니다.
- 포커싱, 스크롤(top, bottom 이동)
- 그 외 전부 useEffect
function MessagesDisplay({messages}) {
const containerRef = React.useRef()
// update, unmount시마다 호출
React.useLayoutEffect(() => {
containerRef.current.scrollTop = containerRef.current.scrollHeight
})
return (
<div ref={containerRef} role="log">
{messages.map((message, index, array) => (
<div key={message.id}>
<strong>{message.author}</strong>: <span>{message.content}</span>
{array.length - 1 === index ? null : <hr />}
</div>
))}
</div>
)
}
useImperativeHandle
when?
- 위의 useLayoutEffect를 사용해야 하는 경우와 유사
- 부모 쪽에서 자식의 useLayoutEffect를 발생 시킬 필요가 있는 경우
- 부모쪽의 ref와 child의 ref 속성 연결
// 1. child 컴포넌트에서
const MessagesDisplay = React.forwardRef(function MessagesDisplay(
{messages},
ref,
) {
const containerRef = React.useRef()
React.useLayoutEffect(() => {
scrollToBottom()
})
function scrollToTop() {
containerRef.current.scrollTop = 0
}
function scrollToBottom() {
containerRef.current.scrollTop = containerRef.current.scrollHeight
}
// ref로 children의 함수를 넘김
React.useImperativeHandle(ref, () => ({
scrollToTop,
scrollToBottom,
}))
return (
<div ref={containerRef} role="log">
{messages.map((message, index, array) => (
<div key={message.id}>
<strong>{message.author}</strong>: <span>{message.content}</span>
{array.length - 1 === index ? null : <hr />}
</div>
))}
</div>
)
})
// 2. 부모 컴포넌트에서
function App() {
// ref 선언
const messageDisplayRef = React.useRef()
const [messages, setMessages] = React.useState(allMessages.slice(0, 8))
const addMessage = () =>
messages.length < allMessages.length
? setMessages(allMessages.slice(0, messages.length + 1))
: null
const removeMessage = () =>
messages.length > 0
? setMessages(allMessages.slice(0, messages.length - 1))
: null
// childRef에서 메소드 접근
const scrollToTop = () => messageDisplayRef.current.scrollToTop()
const scrollToBottom = () => messageDisplayRef.current.scrollToBottom()
return (
<div className="messaging-app">
<div style={{display: 'flex', justifyContent: 'space-between'}}>
<button onClick={addMessage}>add message</button>
<button onClick={removeMessage}>remove message</button>
</div>
<hr />
<div>
<button onClick={scrollToTop}>scroll to top</button>
</div>
// 부모와 자식 연결
<MessagesDisplay ref={messageDisplayRef} messages={messages} />
<div>
<button onClick={scrollToBottom}>scroll to bottom</button>
</div>
</div>
)
}
반응형
'FrontEnd' 카테고리의 다른 글
[Epic React] useCallback과 안전한 비동기 훅 만들기 (0) | 2021.12.04 |
---|---|
[Epic React] useDebug으로 custom hook debugging (0) | 2021.12.04 |
useEffect는 라이프사이클 훅이 아니다. (0) | 2021.12.04 |
[Epic React] useState에서 useReducer로 (0) | 2021.12.03 |
NestJs 관련 학습 컨텐츠 소개 (0) | 2021.12.03 |