공식문서와 서칭을 통해 Hooks를 훑은 후
1. 내가 몰랐거나
2. 헷갈렸던 내용들을 정리해보고자 한다.
👉 참고: (강추) 별코딩 유튜브 React Hooks 재생목록
function heavyWorkd() {
// 뭔가 엄청 무거운 작업
}
useState(()=>{}) // 또는 useState(heavyWork)
useState(heavyWork())
이 아닌, 위의 예시처럼 콜백 형식
으로 무거운 작업을 넣어주면 맨처음 렌더링 될 때 한번에만 불린다.
즉 초기값을 가져올 때 무거운 함수를 가져온다면 콜백 형식으로 넣어주기.
👉 React 공식문서 useState
Mount (화면에 첫 렌더링)
Update (다시 렌더링)
Unmount (화면에서 사라질때)
위의 상황들에서 특정 작업을 실행시켜 주고 싶다면 useEffect를 사용한다.
useEffect(()=>{})
컴포넌트가 렌더링 될때마다 실행
useEffect(()=>{}, [])
[]
즉 dependency의 값이 업데이트 될때만 실행.
만약 dependency가 빈 배열이라면 컴포넌트가 처음 렌더링 될 때에만(Mount) 실행.
useEffect(()=>{
// 실행할 함수(ex. 구독)
return() => {
// 이제 실행을 끝낼 함수(ex. 구독해지)
}
}, [])
const ref = useRef(value)
console.log(ref) // {current: value}
ref.current는 value값을 갖게 된다. {current: value}
언제든 원하는 값으로 바꿀 수 있다. ex. ref.current = "hello"
반환된 ref는 컴포넌트의 전 생애주기를 통틀어서 유지가 된다.
즉, 컴포넌트가 계속해서 렌더링되어도 컴포넌트가 언마운트 되기 전까지는 값을 유지한다.
state 변화 > 렌더링 > 컴포넌트 내부 변수들 초기화
ref 변화 > no 렌더링 > 변수들의 값이 유지됨(내부적으로는 변화가 됨)
그러다가 state 변화 등으로 렌더링이 되면 내부적으로 저장되어 있던 변화가 적용된다.state 변화 -> 렌더링 > 그래도 ref 값은 유지됨
👉 온전히 이해하기 위해 예시참고하기
"렌더링이 된다 -> 함수형 컴포넌트 전체가 다시 불려진다"는 의미.
엄청 자주 바뀌는 값을 state에 넣으면 매번 렌더링 될테니 성능이 줄어들겠지?
그렇다면 변수와의 차이는 뭐가 있을까:
변수는 렌더링 될때마다 선언된 변수가 초기화되니 렌더링 이후 저장되어있던 값들이 초기화 돼서 사라진다 :(
즉, 변화는 감지해야하지만 그 변화가 렌더링을 일으키지 않는 값을 다룰때 useRef를 사용한다!
마치 document.querySelector()
와 같이 사용할 수 있다.
아래 예시를 통해 사용방법을 알아보자:
awesomeRef가 {current: value}를 갖게되는 건 동일하다.
이때 awesomeRef를 태그의 ref 속성에 넣어주기만 하면 된다.
const awesomeRef = useRef(value)
...
<input ref={awesomeRef}/>
ref를 참조하게 만들어 준 후 console.log(awesomeRef)
를 찍어보면
{current: input}
이 들어간걸 확인할 수 있다.
구현해보기
1. 페이지가 렌더링 되면 input칸을 마우스로 클릭하지 않아도 자동으로 focus되도록 구현하고
2. 로그인 버튼을 누르면 입력된 값을 alert창으로 띄우기
import React, {useEffect, useRef} from "react";
const App = () => {
const inputRef = useRef(); //어차피 값을 사용하려는것이 아니니 초기값을 비워줌
useEffect(()=>{
inputRef.current.focus();
}, [])
const handleClick = () => {
alert(`환영합니다 ${input.current.value}!`);
inputRef.current.focus();
}
return (
<div>
<input ref={inputRef} type="text" placeholder="username"/>
<button onClick={handleClick}>로그인</button>
</div>
)
}
export default App