[React] React hook #2

초이·2024년 5월 21일

🌐 React

목록 보기
2/4
post-thumbnail

🧠 Memorization

memorization은 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술이다.

이런 memorization이 왜 react에 필요한지에 알기 위해선 re-rendering에 대해 알아야한다.

♻️ Re-rendering이 일어나는 3가지 조건

  • 컴포넌트에서 state 값이 변경될 때.
  • 부모 컨포넌트의 props가 변경될 때.
  • 부모 컨포넌트가 리렌더링 된 경우 자식 컴포넌트도 리렌더링 된다.

❓ memorization이 왜 필요할까?

위의 그림이 컴포넌트 구조를 나타낼 때, 가장 상위 컴포넌트인 1번 컴포넌트가 리렌더링 조건에 맞아 리렌더링이 일어난다고 하자. 그러면 자식 컴포넌트인 2~7번의 컴포넌트 전부가 리렌더링이 일어나게 된다.

딱 보기에도 리엑트의 장점인 부분 리렌더링의 기능이 돋보이지 않게 된다. 리렌더링이 필요하지 않은 자식 컴포넌트까지 모두 바뀌어 버린다면 자원의 낭비가 클 것으로 예상되기 때문에 우리는 memorization으로 필요한 부분만 리렌더링 되게 사용하는 것이다.

memorization의 종류

  • React.memo : 컴포넌트 memorization
  • useCallback : 함수 memorization
  • useMemo : state memorization

✅ memo(React.memo)


React.memo를 통해 부모컴포넌트의 state 변경으로 본인의 props가 변경하지 않는 이상 React.memo를 한 컴포넌트는 리렌더링 되지 않는다.

  • 부모 컨포넌트 안에 자식 컴포넌트로 Box1, Box2이 있을 때 사용 방법
export default React.memo(Box1);
export default React.memo(Box2);

✅ useCallback


useCallback은 인자로 들어오는 함수를 memorization하는 것이다.
부모 컨포넌트가 리렌더링 되어도 useCallback으로 감싸준 함수는 리렌더링이 되지 않는 것이다.

const initialize = useCallback(()=>{
	setCount(0);
},[]);

이렇게 작성한다면 부모 컨포넌트가 리렌더링 되어도 useCallback안에 있는 함수는 리렌더링이 되지 않는다. useCallback은 의존성 배열을 두번째 인자로 가지고 있는데, 의존성 배열안에 변경시에 함수를 실행하도록 하는 값을 넣으면 된다.


✅ useMemo


useMemo을 캐싱한다.

어떤 자식 컴포넌트 Heavy가 있고, 이 컴포넌트 안에서
엄~~청 많은 계산이 필요한 함수의 리턴 값이 value에 저장된다고 하자.

const value = veryHeavyWork();

부모 컨포넌트가 리렌더링 될 때, 자식 컴포넌트인 Heavy가 계속 리렌더링 되어야하는데, 그렇게 되면 value값을 계속해서 다시 실행하느랴 엄청난 자원을 들여야 한다.

이 value값이 Heavy컴포넌트에서 독자적으로 사용되는 값이라거나 value와 상관없는 값이 부모 컨포넌트에서 변경되어도 자식 컴포넌트라는 이유로 무거운 계산이 계속 리렌더링 된다면, 우리는 useMemo로 value값을 캐싱해서 불필요한 과정을 생략할 수 있다.

const value = useMemo(()=> veryHeavyWork(), []);

마찬가지로 useMemo도 두번째 인자 값으로 의존성 배열을 가지는데, 의존성 배열안의 값이 변경될 때 실행하게 해달라는 의미를 가진다.

💡 그렇다면 모든 값에 memo 값을 넣으면 되겠네!

안된다. memo는 말 그대로 메모리에 공간을 확보해서 값을 맡겨두는 것인데 모든 값에 memorization을 해서 메모리를 불필요하게 낭비하게 된다면 오히려 성능이 악화가 될 수 있다.



🤖 Custom Hook

❓ Custom Hook?

커스텀 훅이란 말 그대로 state를 관리하기 위한 hook을 커스텀하게 만드는 것이다.

🚨 Custom hook을 만들 때 주의사항

  • 이름은 use로 시작해야 한다. (ex. useInput)
  • 파일 이름은 원하는대로 만들어도 된다. (하지만 명시적으로 만들자!)

✅ useInput


만약 우리가 input을 많이 받아야 하는 컴포넌트를 만든다고 하자.

그럴 때 우리는 input의 갯수에 따라 계속해서 useState과 이벤트 핸들러 함수를 만들어야 할 것이다.

  • custom hook 없는 컴포넌트

const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [nickname, setNickname] = useState("");
const [gender, setGender] = useState("");
const [age, setAge] = useState("");
.
.
.
const onChangeEmailHandler = (e) => {} //생략
const onChangePasswordHandler = (e) => {} //생략
const onChangeNicknameHandler = (e) => {}//생략
const onChangeGenderHandler = (e) => {} //생략
.
.
.

handler 안의 내용은 event에서 target의 value를 가져오는 것으로 똑같은 코드가 input의 갯수에 따라 반복되는 것을 볼 수 있다.

이때 우리는 custom hook을 사용해서 코드 중복을 줄일 수 있게 된다.


useInput.js 파일을 만들어서 안에 중복되는 코드를 작성한다면

  • useInput.js

const useInput = () => {
  	//input값 state 관리
	const [value, setValue] = useState('');
  	//input 안의 값을 value에 넣어주는 함수
  	const handler = (e) => {
    	setValue(e.target.value);
    } 
    return [value, handler];
};
export default useInput;
  • useInput 훅을 사용한 컴포넌트

const [email, onEmailHandler] = useInput();
const [password, onPasswordHandler] = useInput();
...

이렇게 input의 value값과 핸들러를 간편하게 작성할 수 있게된다!

profile
개발 일기장

0개의 댓글