react에서 side effect를 수행할 수 있도록 해주는 Hook
리액트 컴포넌트의 외부에서 일어나는 작업들을 말한다.
ex) localStorage와 같은 브라우저API, 서버 API를 통한 요청 등
Side Effect 중 서버에서 많은 양의 데이터를 받아오는 작업을 수행한다고 가정하자.
useEffect를 이용하지 않고 위의 코드를 실행한다고 했을 때,
리렌더링이 될 때마다 해당 작업을 수행해서 프로그램 성능을 저하시킬 것이다.
때문에 Side Effect가 필요할 때만 해당 작업을 수행할 수 있도록 구분하는 것이다.
Side Effect가 필요할 때 특정 작업을 수행하려면 컴포넌트의 생명 주기에 대해 알아야 한다.

처음 컴포넌트가 화면에 나타날 때
처음 컴포넌트가 나타날 때와 변경사항이 있을 때
컴포넌트가 화면에서 사라질 때
해당 컴포넌트에서 구독했던 API 등을 해제하는 뒷정리 함수를 실행한다.
useEffect(function, [deps]);
import React, { useEffect, useState } from "react";
const App = () => {
const [text, setText] = useState("");
const [counter, setCounter] = useState(0);
useEffect(() => {
console.log("Mount!");
}, []);
useEffect(() => {
console.log("rerender!");
});
useEffect(() => {
console.log("counter change!");
}, [counter]);
const handleCounter = () => {
setCounter(counter + 1);
};
const handleText = (e) => {
setText(e.target.value);
};
return (
<>
<div>
<input onChange={handleText} value={text} />
</div>
<div>
<h1>{counter}</h1>
<button onClick={handleCounter}>+1</button>
</div>
</>
);
};
export default App;
react에서 상태 관리를 도와주는 Hook
function App() {
let count = 0;
const handleClick = () => {
count++;
};
return (
<div>
<h1>{count}</h1>
<button onClick={handleClick}>+1</button>
</div>
);
}
export default App;
import React, { useState } from "react";
const App = () => {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
};
return (
<>
<h1>{count}</h1>
<button onClick={handleClick}>+1</button>
</>
);
};
export default App;
const [state, setState] = useState(initialState);
배열 비구조화 할당
위의 예시에서 useState는 아래와 같은 배열을 반환한다.
[S, Dispatch<SetStateAction<S>>]
위 배열의 값들을 변수에 할당하고 싶다고 했을 때
배열을 해체해서 그 값을 각각 변수에 담을 수 있게 하는 문법
setState(newState);
setState((prev)=>prev+1)
성능을 위해 업데이트 작업을 일괄적으로 처리해서 리렌더링 횟수를 최소화하는 기능
import React, { useEffect, useState } from "react";
const App = () => {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const [count3, setCount3] = useState(0);
useEffect(() => {
console.log("render!");
}, [count1, count2, count3]);
const handleClick = () => {
setCount1(count1 + 1);
setCount2(count2 + 1);
setCount3(count3 + 1);
};
return (
<>
<h1>{count1}</h1>
<h1>{count2}</h1>
<h1>{count3}</h1>
<button onClick={handleClick}>+1</button>
</>
);
};
export default App;
성능을 개선해주지만 새로운 값으로 수정하는 방식을 이용했을 때,
같은 state에 대해 동시에 여러 번 수정 작업을 했을 때 마지막 수정 작업만 처리된다.
함수형 업데이트로 위 문제를 해결할 수 있다.
import React, { useEffect, useState } from "react";
const App = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("render!");
}, [count]);
const handleClick = () => {
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
};
return (
<>
<h1>{count}</h1>
<button onClick={handleClick}>+1</button>
</>
);
};
export default App;
batch update를 하기 때문에 수정 작업이 동기적으로 처리될 수 없다.
→수정 작업 이후 수정된 state를 이용한 동기적인 작업에서 변경된 state값을 사용할 수 없다.
import React, { useEffect, useState } from "react";
const UseState = () => {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount((prev) => prev + 1);
alert(count);
};
return (
<>
<h1>{count}</h1>
<button onClick={handleClick}>+1</button>
</>
);
};
export default UseState;
useEffect의 의존성 배열로 위 문제를 해결할 수 있다.
import React, { useEffect, useState } from "react";
const UseState = () => {
const [count, setCount] = useState(0);
useEffect(() => {
alert(count);
}, [count]);
const handleClick = () => {
setCount((prev) => prev + 1);
};
return (
<>
<h1>{count}</h1>
<button onClick={handleClick}>+1</button>
</>
);
};
export default UseState;
Context를 사용할 수 있게 도와주는 Hook
여러 컴포넌트에서 사용하는 값은 보통 props로 전달한다.
하지만 컴포넌트의 deps가 깊어지게 되면
사용하지도 않는 props를 오직 전달하기 위해서 받아오고 전달하는 경우가 있다. (통로가 된 것처럼)
이를 Props Drilling이라고 한다.
이런 문제를 해결하기 위해 전역적으로 값을 공유할 수 있도록 해주는 것이 Context이다.
useContext는 생성된 Context를 사용할 수 있게 도와주는 Hook이다.
const SomeContext = createcContext(defaultValue);
생성된 SomeContext는 지정된 범위 내에서 props로 따로 전달되지 않아도 바로 사용될 수 있다.
생성된 Context를 어떤 범위 내에서 사용할지 Provider를 통해 지정할 수 있다.
<SomeContext.Provider value={someValue}>
<ChildComponent/>
</SomeContext.Provider>
위처럼 Provider로 감싼 자식 컴포넌트에서는 SomeContext값을 이용할 수 있다.
즉 Context.Provider 컴포넌트는 Context 사용 가능한 범위를 본인의 자식 컴포넌트로 지정하는 것이다.
useContext는 지정된 범위 내에서 Context 객체를 가져옴으로써
그 값을 사용할 수 있도록 해주는 Hook인 것이다.
const contextValue=useContext(SomeContext);
위처럼 SomeContext를 전달해서 그 값을 사용할 수 있다.