React에서는 컴포넌트가 표시되고 사라지는 순간까지를 하나의 생명 주기로 표현했습니다.
useEffect(컴포넌트가 표시될 때 실행할 함수, []);
useEffect(오른쪽 리스트에 적은 요소들이 업데이트되는 시점에 실행할 함수, [업데이트 되는지 지켜볼 변수/State]);
useEffect(() => {return () => 컴포넌트가 사라질 때 실행할 함수})
$ yarn create react-app second-app
API호출 대신 setTimeout을 이용해 연습 코드를 작성해보도록 하겠습니다.
import React, {useEffect, useState} from 'react'
function Loading() {
const [isLoaded, setIsLoaded] = useState(false) //1.
useEffect(()=>{ //3.
//컴포넌트가 렌더링될 때 실행될 함수
//데이터 갖고오기 요청보내고, 데이터가 오면 isLoaded = true
setTimeout(() => {
setIsLoaded(true) //4.
},3000)
}, [])
return (
<div>
{isLoaded ? <>로딩완료!</> : <>로딩 중</>} //2.
</div>
)
}
export default Loading
import React, {useEffect, useState} from 'react'
function Loading() {
const [isLoaded, setIsLoaded] = useState(false)
const [text, setText] = useState([]) //2. 새로운 상태값 생성
useEffect(()=>{
setTimeout(() => {
setIsLoaded(true)
},3000)
}, [])
useEffect(() => { // 1. 로딩이 완료로 변화되면 ~가 실행되도록
setText(text.concat(['추가!'])) //3. 업데이트 될 때 실행될 함수
}, [isLoaded])
return (
<div>
{isLoaded ? <>로딩완료!</> : <>로딩 중</>}
{text} //4.
</div>
)
}
export default Loading
isLoaded
를 useEffect
의 두번째 인자의 배열에 넣어줍니다.그런데 추가가 하나가 아닌 두개가 들어간 것을 확인할 수 있습니다.
- 업데이트 될 때 실행되게 만들더라도 처음 컴포넌트가 렌더링될 때 실행이 되기 때문에 2번 실행이 된 것입니다.
- 업데이트 될 때만 실행시키고 싶다면 if문을 추가하면 됩니다.
if(isLoaded) setText(text.concat(['추가!']))
현재 isLoaded에 노란 warning메세지가 뜨는 것을 확인할 수 있습니다.
- 이는 text라는 상태도 지켜보라는 의미입니다.
- 즉 useEffect안에서 사용하고 있는 state값도 배열에 넣으라는 것입니다.
- 단, 의도치 않게 재귀호출을 할 수 있기 때문에 변하지 않을 값이라면 warning이 떠도 괜찮습니다.
import React, {useState, useState} from 'react'
function ButtonRender(){
const [isLoaded, setIsLoaded] = useState(false)
const [loc, setLoc] = useState()
const [subLoc, setSubLoc] = useState([])
useEffect(() => {
setTimeout(()=>{
setIsLoaded(true)
}, 2000)
}, [])
useEffect(() => {
if(loc==='서울') setSubLoc(['명동', '강남'])
if(loc==='부산') setSubLoc(['해운대'])
}, [loc])
return (
<>
{isLoaded && <>
<button onClick={() => {setLoc('서울')}}>서울</button>
<button onClick={() => {setLoc('부산')}}>부산</button>
<p>현재지역: {loc}</p>
<p>세부지역: {subLoc}</p>
</>}
</>
)
}
export default ButtonRender
import React, {useEffect, useState} from 'react'
function Timer({s}) { //s로 props를 받아옵니다.
const [seconds, setSeconds] = useState(s) //받아온 s를 초기값으로 설정
const [isClicked, setIsClicked] = useState(false)
useEffect(() => {
//isClicked가 true일 때 seconds 관찰하며 1초마다 seconds-1
if(isClicked) {
const countDown = setTimout(()=>{
setSecondes(seconds-1)
}, 1000)
}
//isClicked가 false인 경우 unmount
return () => {clearTimeout(countDown)}
}, [seconds, isClicked])
return (
<>
<div>{seconds}</div>
<button onClick={()=>{setIsClikced(true)}}>시작</button>
<button onClick={()=>{setIsClikced(false)}}>중지</button>
</>
)
}
export default Timer
moment플러그인을 이용해 1초씩 시간이 흘러가는 시계를 만들어보세요.
$ yarn add moment moment-timezone
import React, { useState, useEffect } from 'react'
import moment from 'moment'
function TimeZone() {
const [time, setTime] = useState(moment().format('YYYY-MM-DD HH:mm:ss'))
useEffect(() => {
setTimeout(() => {
setTime(moment().format('YYYY-MM-DD HH:mm:ss'))
}, 1000)
}, [time])
return <div>{time}</div>
}
export default TimeZone