Introduction
state를 변경하면 모든 component는 다시 실행되고 모든 code들도 다시 실행된다.
const App = () => {
const [counter, setCounter] = React.useState(0);
const onClick = () => setCounter((current) => current + 1);
console.log("call an api");
return (
<div>
<h3>{counter}</h3>
<button onClick={onClick}>Click me</button>
</div>
);
};
리렌더링 될 때마다 반복 실행되어도 괜찮은 코드도 있을 테지만, 컴포넌트가 처음 render 될 때만 코드가 실행되길 원할 수도 있다. 예를들어, API로 외부 데이터를 가져올 때 컴포넌트 처음 렌더링되는 그 순간에만 API 요청을 하고 이후에 state가 변화할 때는 그 API에서 똑같은 정보를 가져오고 싶지는 않을 것이다.
이렇게 특정 코드들이 첫번째 component render에서만 실행되게 하려면 useEffect를 사용하면 된다.
useEffect
useEffect는 두 개의 argument를 가지는 함수인데, 첫 번째 argument는 실행하고 싶은 코드고, 두 번째는 Deps 배열을 넣는데 이는 dependency(지켜보려는 것)이다. 즉, Deps를 통해 내가 원하는 부분을 지정하여 그 부분만을 변화시킬 수 있다.
Deps부분에 빈 배열을 넣어주면 처음 실행됐을 때만 render된다.
const App = () => {
const [counter, setCounter] = React.useState(0);
const onClick = () => setCounter((current) => current + 1);
console.log("i run all the time");
const iRunOnlyOnce = () => {
console.log("i run only once");
};
React.useEffect(iRunOnlyOnce, []);
return (
<div>
<h3>{counter}</h3>
<button onClick={onClick}>Click me</button>
</div>
);
};
참고로 useEffect는 화면이 다 그려지고 나서 실행된다. memo랑 헷갈릴 수 있는데 이는 라이프 사이클이랑 연관이 있는 함수이고, 최초 실행만 할 것이냐, 아니면 props, state에 따라 렌더링시 다시 그릴것이냐 판단하는 함수다.
Deps
이번엔 특정 코드가 바뀔 때마다 실행되게 해보자. Deps에 감지하고자 하는 변수를 넣으면 된다.
const App = () => {
const [counter, setCounter] = React.useState(0);
const [keyword, setKeyword] = React.useState("");
const onClick = () => setCounter((current) => current + 1);
const onChange = () => setKeyword(event.target.value);
console.log("i run all the time");
React.useEffect(() => {
console.log("I run only once.");
}, []);
React.useEffect(() => {
console.log("I run when 'keyword' changes.", keyword);
}, [keyword]);
React.useEffect(() => {
console.log("I run when 'counter' changes.");
}, [counter]);
return (
<div>
<input
value={keyword}
onChange={onChange}
type="text"
placehoder="Search here..."
/>
<h3>{counter}</h3>
<button onClick={onClick}>Click me</button>
</div>
);
};
아래와 같이 여러개를 지정할 수도 있다.
React.useEffect(() => {
console.log("I run when 'keyword & counter' changes.");
}, [keyword, counter]);
이렇게 불필요한 리렌더링을 피하기 위해 React.js가 따로 준비한 것이 바로 useEffect이다.
Cleanup function
const Hello = () => {
React.useEffect(() => {
console.log("created");
}, []);
return <h1>Hello</h1>;
};
const App = () => {
const [showing, setShowing] = React.useState(false);
const onClick = () => setShowing((prev) => !prev);
return (
<div>
{showing && <Hello />}
<button onClick={onClick}>{showing ? "Hide" : "Show"}</button>
</div>
);
};
Show 버튼을 누를때마다 useEffect가 실행된다.
참고로 요소를 숨기는게 아니라 없애버리는 것이다. 다음 사진을 보면 요소가 아예 없어지는 것을 확인할 수 있다.
destory될 때 실행할 함수를 지정하려면 useEffect 안에 return을 넣으면 된다.
React.useEffect(() => {
console.log("created");
return () => console.log("destroyed")
}, []);
이제 Hide를 통해 컴포넌트가 없어질 때 해당 함수가 실행된다.
이는 예를 들어 할 일을 다 끝내고 API분석 결과를 보낼 때 사용한다.
총 정리
지금까지 배운 것을 간략히 정리하면 다음과 같다.
- 리액트를 사용하는 이유: 최소 단위의 렌더링을 위해
- useState(): 변수, 변수를 제어하는 함수로 구성되며 변하는 값을 제어, 해당 부분의 리렌더링을 위함이다.
- props: 태그의 속성 값을 함수의 argument처럼 컴포넌트에 값을 전달해준다.
- 부모 컴포넌트에서 리렌더링이 일어날 경우 모든 자식들이 리렌더링이 된다.(memo를 사용할 수 있다)
- propType을 설치하고 props의 타입을 지정해 줄 수 있다. 이 때 isRequired로 필수값을 지정할 수 있다.
- useEffect(): 코드의 실행 시점을 관리할 수 있는 선택권을 얻는 방어막 같은 존재, dependency가 없을 경우 최초 1회 실행, 있을 경우 해당 값이 변할 경우 실행한다. dependency는 여러개 입력이 가능하다.
- CleanUp 함수를 통해 뒷처리(destory)를 할 수 있다.
참고 : NomadCoders - ReactJS로 영화 웹 서비스 만들기 강좌
'React' 카테고리의 다른 글
props, PropTypes, memo (0) | 2023.02.18 |
---|---|
useState를 이용해 단위변환 기능 만들기 (0) | 2023.02.18 |
state, setState (0) | 2023.02.18 |
[JSCODE] React 3회차 미션 (1) | 2023.02.17 |
[JSCODE] React 2회차 심화미션 (1) | 2023.02.14 |