클래스 컴포넌트 문제
- 클래스 개념 어려움
- 클래스형 컴포넌트의 복잡함
- 컴포넌트 사이에서 상태 로직 재사용의 어려움
초기 함수형 컴포넌트 문제
- 클래스 형 컴포넌트는 렌더링할 때 render 함수만 호출 되므로 나머지 method 및 state는 보존
- 함수형 컴포넌트는 함수안에 모든 로직이 다시 실행되므로 기존의 state 값을 보존하지 못하는 문제 발생 =>
함수형 컴포넌트가 리렌더링될 때 무조건 새롭게 선언, 초기화, 할당 과정이 수행된다.
// class 형
class App extends Component {
constructor(props) {
super(props);
this.state = {
name: "park",
age: 7,
};
}
render() {
return (
<>
<div>{this.state.name}</div>
<div>{this.state.age}</div>
</>
);
}
}
// 함수형
function App() {
const state = {
name: "park",
age: 7,
};
return (
<>
<div>{state.name}</div>
<div>{state.age}</div>
</>
);
}
useState
useState
- 함수형 컴포넌트에서 state 관리 및 사용 가능하도록 함
const Count = () => {
const [count, setCount] = useState(0);
return (
<div>
<div>{count}</div>
<button onClick={() => setCount((prev) => prev + 1)}>+</button>
<button onClick={() => setCount((prev) => prev - 1)}>-</button>
</div>
);
};
useEffect
- useEffect는 클래스 컴포넌트의 componentDidMount, ComponentDidUpdate, componentWillUnmount 라이프 싸이클 메소드와 비슷한 역할은 하지만 다른 개념이다.
- 두번째 전달인자에 아무것도 넣지 않으면 re-render 될 때 마다 effect 수행, 빈 배열을 넣으면 컴포넌트가 마운트될 때만 콜백함수 호출, 배열안에 state 관련 변수를 넣게 되면 해당 state가 변할 때만 콜백함수 호출
- clean-up 함수를 통해 이전 콜백 함수의 호출에 의해 특정 이벤트 및 DOM을 참조 하고 있는 경우 이벤트 제거 및 DOM 참조를 제거할 수 있다.
const Count = () => {
const [count, setCount] = useState(0);
const [name, setName] = useState("park");
useEffect(() => {
console.log("hi");
document.title = `업데이트 횟수:${count}`;
}); // 두 번째 전달 인자에 [count] 입력하면 count state가 수정되었을 때만 effect 호출
const onClickIncrement = () => {
setCount(count + 1);
};
return (
<div>
<div>{count}</div>
<button onClick={onClickIncrement}>증가</button>
<div>{name}</div>
<button onClick={() => setName(name === "park" ? "lee" : "park")}>
이름 변경
</button>
</div>
);
};
useContext
- 전역으로 props 및 함수를 필요한 곳에만 사용할 수 있도록 하는 Hook
// context 생성
import { createContext } from "react";
export const NameContext = createContext(null);
// context Provider 설정 및 value 전달
import Ex from "./Ex";
import { NameContext } from "./useContext";
function App() {
const introduce = {
name: "park",
age: 27,
};
return (
<NameContext.Provider value={introduce}>
<Ex />
</NameContext.Provider>
);
}
export default App;
// context 사용
import { useContext } from "react";
import { NameContext } from "./useContext";
const Ex = () => {
const { name, age } = useContext(NameContext);
return (
<div>
<div>{name}</div>
<div>{age}</div>
</div>
);
};
export default Ex;
useCallback
- 렌더링 최적화를 위해 사용
- React 특성상 re-render 될 때마다 함수를 선언한 곳에서 함수가 새로 만들어 지기 때문에 새로 만들어진 함수로 하위 컴포넌트가 re-render되는 문제를 예방
- dependecy에 빈 배열을 사용하게 되면 초기 함수를 계속 가지고 있으므로 업데이트 확인을 위해서 함수를 호출했을 때 변경된 state를 볼 수 없음 => update 된 값을 확인하고 싶다면 dependency에 state 변수를 입력해서 해당 state가 변경될 때만 함수가 새롭게 만들어지도록 구현
- 만약 useCallback의 dependency배열에 들어가는 state가 re-render 될 때 마다 update되는 데이터라면 굳이 사용하지 않아도 됨
function App() {
const [count, setCount] = useState(0);
const noticeCount = () => {
console.log("count Up!");
};
const noticeCount = useCallback(() => {
console.log(count);
}, []);
const noticeCount = useCallback(() => {
console.log(count);
}, [count]);
useEffect(() => {
console.log("re-render");
}, [noticeCount]);
return (
<>
<div>
<div>{count}</div>
<button onClick={() => setCount((prev) => prev + 1)}>+</button>
<button onClick={() => setCount((prev) => prev - 1)}>-</button>
<button onClick={noticeCount}>카운터 값 확인</button>
</div>
</>
);
}
useMemo
- 성능 최적화를 위해 사용
- 첫 번째 매개변수로 설정한 콜백함수의 return 값을 저장하고 있다가 두번째 매개변수로 설정한 값이 수정되지 않으면 재사용
- dependency 배열에 설정한 값이 수정되면 값을 초기화
- dependency 배열을 빈 배열로 설정하면 콜백함수 내부에서 사용되고 있는 상태값은 초기값을 참조
- dependency 배열에 의존성 데이터를 설정하면 해당 데이터가 업데이트되면 콜백함수 내부에서 업데이트 된 의존성 데이터를 기반으로 다시 계산, 반환, 메모이제이션
function App() {
const [count, setCount] = useState(0);
const [name, setName] = useState("park");
const noticeCount = `${count} ${name}`;
const noticeCount = useMemo(() => `${count} ${name}`}, []);
const noticeCount = useMemo(() => `${count} ${name}`, [count]);
useEffect(() => {
console.log("re-render");
console.log(noticeCount);
}, [noticeCount]);
return (
<>
<div>
<div>{count}</div>
<button onClick={() => setCount((prev) => prev + 1)}>+</button>
<button onClick={() => setCount((prev) => prev - 1)}>-</button>
<button
onClick={() => setName((prev) => (prev === "park" ? "lee" : "park"))}
>
이름 변경
</button>
</div>
</>
);
}
useRef
- DOM에 접근할 수 있도록 하는 Hook
- 접근시에 cuurent property 사용
- rendring과 관련 없는 변수에 사용
// DOM 접근
function App() {
const ref = useRef(null);
const focusElement = () => {
ref.current.focus();
};
return (
<div>
<input type="text" ref={ref} />
<button onClick={focusElement}>포커스 시작</button>
</div>
);
}
// rendring과 관련 없는 변수에 사용
function App() {
const [count, setCount] = useState(0);
const intervalRef = useRef(0);
useEffect(() => {
// 좋은 코드는 아닌 것 같음
// setCount를 해당 로직에서만 사용하면 문제가 없는데 다른 곳에서 사용하게되면 문제가 될 수 있음
intervalRef.current = setInterval(() => setCount((prev) => prev + 1), 1000);
}, []);
const stopInterval = () => {
clearInterval(intervalRef.current);
};
return (
<div>
<div>{count}</div>
<button onClick={stopInterval}>Stop Count Up</button>
</div>
);
}
Hook 규칙
1. React 컴포넌트의 최상위(at the Top Level)에서만 Hook을 호출 => 렌더링 될 때마다 항상 동일한 순서로 Hook이 호출 되는 것을 보장해야 함
2. 함수형 컴포넌트 및 Custom Hook Hook에서 호출 가능
3. 반복문, 조건문 혹은 중첩된 함수 내에서 Hook을 호출하면 안됨
4. eslint-plugin-react-hooks 라는 ESLint 플러그인이 1, 2번 규칙을 강제하도록 함(CRA에 기본 설정 되어있음)
왜 반복문, 조건문 혹은 중첩된 함수 내에서 Hook을 호출하면 안될까?
- React는 Hook이 호출되는 순서에 의존
// useState(비슷한 형태)
let _value;
export useState(initialValue){
if (_value === 'undefined') {
_value = initialValue;
}
const setValue = newValue => {
_value = newValue;
}
return [_value, setValue];
}
클로저
이용선언된 컴포넌트를 유일하게 구별할 수 있는 키
로 접근할 수 있는 배열로 저장 되있음(순서대로 저장 되있음
)React Hooks 총정리
https://velog.io/@goyou123/React-Hooks-%EC%B4%9D%EC%A0%95%EB%A6%AC/
클래스형과 함수형 차이
https://velog.io/@sdc337dc/0.%ED%81%B4%EB%9E%98%EC%8A%A4%ED%98%95-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8
프론트엔드 기술 저장소
https://k-developer.gitbook.io/dev/react/react-hook
useContext란? React hooks useContext란?
https://ko-de-dev-green.tistory.com/67
useContet 사용법 및 예제
https://itprogramming119.tistory.com/entry/React-useContext-%EC%82%AC%EC%9A%A9%EB%B2%95-%EB%B0%8F-%EC%98%88%EC%A0%9C
useState Hook과 클로저
https://velog.io/@ggong/useState-Hook%EA%B3%BC-%ED%81%B4%EB%A1%9C%EC%A0%80
공식문서
https://ko.reactjs.org/docs/hooks-intro.html