컴포넌트가 표시되고 사라지는 순간까지를 하나의 생명 주기라 한다.
크게 세 가지로 시점을 나눌 수 있다.
mount
→ update
→ unmount
useEffect가 하는 일
useEffect Hook을 이용하여 우리는 React에게 컴포넌트가 렌더링 이후에 어떤 일을 수행해야하는 지를 말합니다. React는 우리가 넘긴 함수를 기억했다가(이 함수를 ‘effect’라고 부릅니다) DOM 업데이트를 수행한 이후에 불러낼 것입니다. 위의 경우에는 effect를 통해 문서 타이틀을 지정하지만, 이 외에도 데이터를 가져오거나 다른 명령형(imperative) API를 불러내는 일도 할 수 있습니다.
useEffect를 컴포넌트 안에서 불러내는 이유
useEffect를 컴포넌트 내부에 둠으로써 effect를 통해 count state 변수(또는 그 어떤 prop에도)에 접근할 수 있게 됩니다. 함수 범위 안에 존재하기 때문에 특별한 API 없이도 값을 얻을 수 있는 것입니다. Hook은 자바스크립트의 클로저를 이용하여 React에 한정된 API를 고안하는 것보다 자바스크립트가 이미 가지고 있는 방법을 이용하여 문제를 해결합니다.
React 컴포넌트는 기본적으로 내부 상태(state)가 변할 때 마다 다시 랜더링(rendering)이 된다. 다시 랜더링 되어도 동일한 참조값을 유지하고 싶을때 이용하는 것이 useRef
이다.
getElementById
등과 동일한 역할을 한다고 생각하면 된다.import React, { useRef } from 'react'
function Refs() {
const a = useRef()
const keyHandler = () => {
console.log(a.current.value)
}
return (
<>
<input ref={a} onKeyDown={keyHandler}/>
</>
)
}
export default Refs
import React, { useRef } from 'react'
function Refs() {
const a = useRef(0)
const keyHandler = () => {
console.log(a.current + 1)
}
return (
<>
<p>{a.current}</p>
<button onClick={keyHandler}>버튼!</button>
</>
)
}
export default Refs
import React, { useState, useEffect } from 'react'
function Login() {
const [userInput, setUserInput] = useState({id: '', pw: ''})
const onUserInputChange = (e) => {
const { name, value } = e.target
setUserInput({...userInput, [name]:value})
}
const doLogin = () => {
alert('로그인 완료!')
}
return (
<div>
<input
placeholder="아이디를 입력하세요"
value={userInput.id}
name="id"
onChange={onUserInputChange} />
<input
placeholder="비밀번호를 입력하세요"
type="password"
value={userInput.pw}
name="pw"
onChange={onUserInputChange}
onKeyDown={(e) => {if(e.key==="Enter"){doLogin()}}} />
<button onClick={doLogin}>
로그인
</button>
</div>
)
}
export default Login
value
값에서 useState
의 id
에 접근하기위해 점 표기법 사용onChange
에 들어갈 함수에서 스프레드 연산자를 사용해서 기존의 input
객체를 복사 하기 name
키를 가진 값을 value
로 설정useEffect(컴포넌트가 표시될 때 실행할 함수, [여기는 빈 대괄호입니다]);
useEffect(오른쪽 리스트에 적은 요소들이 업데이트되는 시점에 실행할 함수, [업데이트 되는지 지켜볼 변수/State]);
useEffect(() => {return () => 컴포넌트가 사라질 때 실행할 함수})
const [isLoaded, setIsLoaded] = useState(false)
삼항연산자 활용
{조건문 ? 참일때 실행될 부분 : 거짓일때 실행될 부분}
의 형태
<div>
{isLoaded ? <>로딩완료!</> : <>로딩 중</>}
</div>
onClick
: 클릭하면 특정한 함수가 실행되도록 하기 위한 이벤트 핸들러
onChange
: input 태그에서 내부 내용이 바뀔 때 실행될 함수를 지정
onFocus
: input 태그에 포커싱되었을 때 실행될 함수를 지정
onBlur
: 포커스가 풀렸을 때 실행될 함수를 지정할 수 있습니다.
onKeyDown
: 키를 눌렀을 때 실행되는 함수를 지정
*onKeyPress 는 사용을 지양한다.
...userInput
...userInput 과 같이 ...
을 사용하는 것을 spread operator
라고 한다. 특정한 상태 내부의 값들을 펼쳐서 담고자 할 때 쓰는 문법이다.
spread operator 는 내부의 값이 어떤 것이 있는지 명확한 경우에만 사용한다. 명확하지 않은 경우에는 아예 사용하지 않는 것이 좋다.
유저가 시간초를 설정할 수 있는 타이머 만들기
[세부사항]
onChange
를 활용해서, 유저가 입력한 값 그대로 타이머에 반영되도록 해보세요.[해답 및 해석]
import React, { useState, useRef, useEffect } from 'react'
function Timer() {
const [seconds, setSeconds] = useState(60)
const [isClicked, setIsClicked] = useState(false)
const inputRef = useRef()
// Enter키를 누르면 inputHandler 함수 실행
const inputHandler = () => {
// ref는 객체이며 current 프로퍼티를 가지고 있다.
// 객체를 통해 DOM에 직접적인 접근이 가능하다 current.value
const { value } = inputRef.current
setSeconds(value)
}
useEffect(() => {
if (isClicked) {
const countDown = setTimeout(() => {
if (seconds > 0) {
// 초가 0보다 크면, 1을 감소시킨다.
setSeconds(seconds - 1)
} else if (seconds === 0) {
// 만약에 초가 0이 되면, 해당 함수가 실행되는 걸 멈춘다.
clearTimeout(countDown)
}
}, 1000)
// 페이지에서 벗어나면, 해당 함수도 이제는 작동하지 않도록 없애준다.
return () => clearTimeout(countDown)
}
// seconds, isClicked 가 변하는 것을 감지한다.
// 타이머 시작으로 인해 isClicked가 변하고 true값이 되어 조건문 통과
}, [seconds, isClicked])
return (
<div>
<input
ref={inputRef}
onKeyDown={(e) => {
if (e.key === 'Enter') {
inputHandler()
}
}}
></input>
<button onClick={inputHandler}>타이머 설정</button>
<h1>우리의 타이머</h1>
<h1>{seconds}</h1>
<button onClick={() => setIsClicked(true)}>타이머 시작</button>
<button onClick={() => setIsClicked(false)}>타이머 중지</button>
</div>
)
}
export default Timer