앞서 React에서 사용하는 hook 중 하나인 useState
에 대해 알아봤었다.
오늘은 그 외에 다른 hook들에 대해 알아보려 한다.
- useEffect
- 사용 목적
- 리렌더링 시 문제점
- useRef
- 사용 방법
- 사용 목적
useEffect는 리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook이다. 1)어떤 컴포넌트가 화면에 보여졌을 때 내가 무언가를 실행하고 싶거나 2)어떤 컴포넌트가 화면에서 사라졌을 때 무언가를 실행하고 싶을 때 useEffect를 사용한다.
import React, { useEffect } from "react";
const App = () => {
useEffect(() => {
// 이 부분이 실행된다.
console.log("hello useEffect");
});
return <div>Home</div>;
}
export default App;
{useEffect}
를 리액트로 import
한 후,
return 할 값 위에 useEffect
함수를 만들어 실행하고자 하는 로직을 넣어주면 된다. 그러면 브라우저가 실행될 때, useEffect
안의 console.log가 실행된다.
1) input에 값을 입력
2) value, 즉 state가 변경
3) state가 바뀌었기 때문에 App컴포넌트 리렌더링
4) 리렌더링 -> useEffect()
5) 1~4번 계속 반복 (인풋창에 값이 변경될때마다 렌더링 새로 하고 있다는거임!)
이를 해결하기 위해 의존성 배열(dependency array)
을 사용할 수 있다.
그게 뭘까?
이 배열에 값을 넣으면, 그 값이 바뀔 때만 useEffect를 실행한다! 라는 뜻이다.
그저 []
이 배열만 하나 추가하는 것이다. 물론 이 안에 값을 넣어줘도 되기는 하는데, 공백으로 놔두면 어떤 값이 들어와도 바뀌었다고 볼 수 없으니까 처음에 렌더링이 될 때만 useEffect를 실행하고, 그 다음엔 실행하지 않는다. 즉, 리렌더링이 일어나지 않는다는 말이다!
그럼 의존성 배열 자리에 값을 넣어주면 console.log
는 어떻게 실행될까 ?
useEffect(() => {
console.log(`hello useEffect! : ${value}`);
}, [value]);
이렇게 적어주면 인풋창 값 변경될 때마다, 렌더링 될 때 마다 변경되는 값을 확인할 수 있다.
DOM 요소에 접근할 수 있게 해주는 hook
을 말한다.
이런 식으로 사용 가능하다.
위 코드 대로 콘솔을 띄우면, 이런 식으로 값 변경도 가능하다.
이렇게 설정된 ref 값은 컴포넌트가 계속해서 렌더링이 되어도, 컴포넌트가 unmount, 즉 죽기 전까지는 값을 유지한다 !!!
1. 저장공간
코드와 화면을 통해 결과를 보자!
import React, { useRef, useState } from 'react';
const style = {
border: '1px solid black',
margin: '10px',
padding: '10px',
};
function App() {
const [count, setCount] = useState(0);
const countRef = useRef(0);
const plusStatecountButtonHandler = () => {
setCount(count + 1);
};
const plusRefcountButtonHandler = () => {
countRef.current++;
console.log(countRef.current);
};
return (
<>
<div style={style}>
state 영역입니다.{count} <br />
<button onClick={plusStatecountButtonHandler}>state 증가</button>
</div>
<div style={style}>
ref 영역입니다. {countRef.current}
<br />
<button onClick={plusRefcountButtonHandler}>ref 증가</button>
</div>
</>
);
}
export default App;
state 문법과 ref 문법을 사용해 작성한 코드로 각자의 공간과 버튼을 만들었다.
둘다 버튼을 누르면 박스 안에 적힌 숫자가 1씩 증가하도록 하는 로직이 작성되었다.
하지만 ?
ref 영역은 아무리 버튼을 눌러도 콘솔창에서만 숫자가 증가되고, 브라우저에서는 반영이 되지 않는 모습을 볼 수 있다!
정리하면,
2. 원하는 DOM 접근 위해
import React, { useEffect, useRef, useState } from 'react';
function App() {
const idRef = useRef('');
// 화면이 렌더링 될 때, 어떤 작업을 하고 싶다 ! : useEffect !
useEffect(() => {
idRef.current.focus();
}, []);
return (
<>
<div>
아이디 : <input type='text' ref={idRef} />
</div>
<div>
비밀번호 : <input type='password' />
</div>
</>
);
}
export default App;
import React, { useEffect, useRef, useState } from 'react';
function App() {
const idRef = useRef('');
const pwRef = useRef('');
const [id, setId] = useState('');
// 화면이 렌더링 될 때, 어떤 작업을 하고 싶다 ! : useEffect !
useEffect(() => {
idRef.current.focus();
}, []);
useEffect(() => {
if (id.length >= 10) {
pwRef.current.focus();
}
}, [id]);
return (
<>
<div>
아이디 :{' '}
<input
value={id}
onChange={(event) => {
setId(event.target.value);
}}
type='text'
ref={idRef}
/>
</div>
<div>
비밀번호 : <input type='password' ref={pwRef} />
</div>
</>
);
}
export default App;
초기 아이디 값 부여하고, 비밀번호에도 const pwRef = useRef('');
이렇게 Ref
로 만들어준다.
그리고 추가 useEffect
를 만들어 그 안에 if
문으로 조건 만들어주고, Onchange
속성에 변경될 id
걸어주면 끝!
근데, 굳이 useEffect
하나 더 만들어서 비밀번호 창으로 이동시키는거 말고, id
Onchange
속성에다가 자리수가 10자리이면 비밀번호창으로 옮겨지는 코드 적어주면 안되나? 라고 말할 수 있다.
그럼 바로 실행 해보면 되지 !
import React, { useEffect, useRef, useState } from 'react';
function App() {
const idRef = useRef('');
const pwRef = useRef('');
const [id, setId] = useState('');
// 화면이 렌더링 될 때, 어떤 작업을 하고 싶다 ! : useEffect !
useEffect(() => {
idRef.current.focus();
}, []);
// useEffect(() => {
// if (id.length >= 10) {
// pwRef.current.focus();
// }
// }, [id]);
return (
<>
<div>
아이디 :{' '}
<input
value={id}
onChange={(event) => {
setId(event.target.value);
console.log('id', id);
if (id.length >= 10) {
pwRef.current.focus();
}
}}
type='text'
ref={idRef}
/>
</div>
<div>
비밀번호 : <input type='password' ref={pwRef} />
</div>
</>
);
}
export default App;
위의 useEffect
는 잠시 주석처리하고, onChange
에 로직을 넣어봤다.
이제 실행해보자.
분명히 10자리 치면 비밀번호 창으로 넘어가기로 했는데,
11자리를 쳐야 넘어간다.
콘솔창에 뜨는 것도 input창에 친 값보다 하나씩 늦게 반환된다.
setId
를 했다고 바로 적용이 되는 것이 아니다.
리액트는 batch update
로 처리하기 때문이다!
그게 뭐냐면, 리액트 성능을 위해 setState를 단일 업데이트 (batch update)로 한번에 처리한다는 거다. 즉, 모아서 한 번에 처리하기 때문에 늦게 반환될 수도 있다는 것!
이렇게 벌써 useState
, useEffect
, useRef
, 세 개의 React hook
을 알게 되었다.
부지런히 코드 쳐봐야 좀 익숙해질 수 있을 것 같다.