이 포스트는 전에 올렸던 React Hooks의 종류 및 개념에 대한 총 정리를 이어서 작성하는 글 입니다.
useReducer()
const [state, dispatch] = useReducer(reducer, initialState, init);
import React, { useReducer } from "react";
function init(initialState) {
return { count: initialState };
}
function reducer(state, action) {
switch (action.type) {
case "INCREMENT":
return { count: state.count + action.payload };
case "DECREMENT":
return { count: state.count - action.payload };
case "RESET":
return init(action.payload);
default:
throw new Error("unsupported action type: ", action.type);
}
}
const Counter = ({ initialCount }) => {
const [state, dispatch] = useReducer(reducer, initialCount, init);
return (
<>
<h2>{state.count}</h2>
<button onClick={() => dispatch({ type: "RESET", payload: 0 })}>
초기화
</button>
<button onClick={() => dispatch({ type: "INCREMENT", payload: 1 })}>
증가
</button>
<button onClick={() => dispatch({ type: "DECREMENT", payload: 1 })}>
감소
</button>
<button onClick={() => dispatch({ type: "errrrrrrrrr", payload: 1 })}>
에러
</button>
</>
);
};
export default Counter;
useCallback()
function App() {
const [name, setName] = useState('');
/*
const onSave = () => {};
useCallback을 사용하지 않으면, Profile 컴포넌트에서 React.memo를 사용해도 이전 onSave와 이후 onSave가
매번 다르게 되기 때문에 매번 렌더링이 된다. 그러므로, Profile컴포넌트의 리렌더링을 방지하기 위해 useCallback을
사용한다.
*/
const onSave = useCallback(() => {
console.log(name)
},[name]);
return (
<div className="App">
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<Profile onSave={onSave} />
</div>
);
}
useMemo()
object는 객체 타입이기 때문에, 원시타입과는 다르게 값이 저장될 때 주소 값으로 저장이된다. 즉, 메모리 상의 주소가 다르게 저장되어 있는 것인데, 예시의 객체는 눈으로 보이기에는 똑같지만 저장된 메모리 상의 주소가 완전히 다르기 때문에 useEffect의 lunch는 변경이 되었다고 생각할 수 있다.
const lunch = { meal: isKorean ? '한식' : '일식' };
useEffect(() => {
console.log('useEffect... 호출');
}, [lunch])
따라서, 이것을 해결해 주려면 useMemo를 사용해서 memoization해주면 된다.
import { useMemo, useEffect, useState } from 'react';
function App() {
const [number, setNumber] = useState(0);
const [isKorean, setIsKorean] = useState(true);
const lunch = useMemo(() => {
return {
meal: isKorean ? '한식' : '일식'
}
}, [isKorean])
useEffect(() => {
console.log('useEffect... 호출');
}, [lunch])
return (
<div>
<h2>하루에 몇 끼 먹어요?</h2>
<input type="number" value={number} onChange={(e) => setNumber(e.target.value)}/>
<hr/>
<h2>어느 음식 먹어요?</h2>
<p>종류: {lunch.meal}</p>
<button onClick={() => setIsKorean(!isKorean)}>Update</button>
</div>
);
}
export default App;