Hooks 는 리액트 v16.8 에 새로 도입된 기능으로 함수 컴포넌트에서도 상태 관리를 할 수 있는 useState
렌더링 직후 작업을 설정하는 useEffect 등의 기능을 제공하여 기존의 함수 컴포넌트에서 할 수 없었던
다양한 작업을 할 수 있게 해줍니다.
여기서 배울 부분은 정말 간단하게 설명하는 부분이기 때문에 혹시나 깊게 배우고
싶다면 제 velog 에 하나하나 정리한 부분을 공부하시면 됩니다.
만약 함수컴포넌트에서 상태를 관리해야 한다면 이 Hook 을 사용하면 됩니다.
useState 함수의 파라미터에는 상태의 기본값을 넣어줍니다.
useState 함수가 호출되면 배열을 반환하는데 그 배열의 첫 번째 원소는 상태값
두번째 원소는 상태를 설정하는 함수가 들어갑니다.
상태를 설정하는 함수에 파라미터를 넣어서 호출하면 전달받은 파라미터로 값이 바뀌고 컴포넌트가 정상적으로 리렌더링됩니다.
기본값 : const [상태값 , 상태를 설정하는 함수] = useState(기본값);
import { useState } from 'react'
const Counter = () => {
const [value, setValue] = useState(0);
return (
<div>
<p>{value}</p>
<button onClick={() => setValue(value + 1)}>+1</button>
<button onClick={() => setValue(value - 1)}>-1</button>
</div>
)
};
export default Counter;
useState 여러번 사용하기
import{ useState } from 'react';
const Info() => {
const [name, setName] = useState('');
const [nickname, setNickname] = useState('');
const onChangeName = e => {
setName(e.target.value);
}
const onChangeNickname = e => {
setNickname(e.target.value);
}
return(
<div>
<div>
<input value = { name } onChange = { onChangeName } />
<input value = { nickname } onChange = { onChangeNickname } />
</div>
<div>
<p> {name} </p>
<p> {nickname} </p>
</div>
</div>
)
}
export default Info;
useEffect 함수의 첫 번째 매개변수로 전달된 함수는 컴포넌트가 렌더링될 때마다 실행됩니다.
이 함수는 일반적으로 API 호출, DOM 조작, 타이머 등과 같은 작업을 수행합니다.
두 번째 매개변수로 전달되는 배열은 의존성(dependency) 배열입니다.
이 배열은 useEffect 함수가 실행되는 조건을 설정하며, 배열에 포함된 값이 변경될 때만
useEffect 함수가 다시 실행됩니다. 따라서, useEffect 함수 내에서 의존성 배열에 포함되지 않은 값은
변경되어도 useEffect 함수는 실행되지 않습니다.
useEffect 함수는 컴포넌트 내에서 상태(state)나 props가 변경될 때마다 실행되며, 그 안에 작성된 코드를 실행합니다.
이 코드 내에서 발생하는 작업들을 "side effect" 라고 부릅니다.
기본값 : useEffect(() => {}, [])
import{ useState, useEffect } from 'react';
const Info = () => {
const [name, setName] = useState('');
const [nickname, setNickname] = useState('');
useEffect(() => {
console.log('렌더링 완료!!');
console.log({name, nickname})
})
export default MyComponent;
......
여기서 [ ] 를 넣어주지 않는다면 렌더링 될 때마다 실행됩니다.
[ ] 를 빈 배열로 넣어주게 되면 처음 홈페이지를 렌더링할때만 실행되고 그 이후로는 실행되지 않습니다.
useEffect의 mount 와 unmount
컴포넌트가 마운트될 때는, 컴포넌트가 화면에서 나타날 때입니다.
컴포넌트가 언마운트될 때는, 컴포넌트가 화면에서 사라질 때입니다.
여기서 중요한건 unmount 입니다.
이는 컴포넌트가 더 이상 필요하지 않을 때 발생합니다.
예를 들어, 다른 페이지로 이동하거나, 다른 컴포넌트로 교체될 때, 컴포넌트가 언마운트됩니다.
컴포넌트가 언마운트될 때는 useEffect 함수에서 반환하는 함수가 실행되는데,
컴포넌트가 마운트될 때 등록한 이벤트 리스너나 타이머 등을 제거해야 할 경우 쓰입니다.
이렇게 함으로써, 메모리 누수를 방지하고, 앱의 성능과 안정성을 유지할 수 있습니다.
기본값 : useEffect(() => { return () }, [])
import React, { useState, useEffect } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
// 컴포넌트가 마운트될 때 실행될 코드
console.log('Component mounted');
// 컴포넌트가 언마운트될 때 실행될 함수를 반환
return () => {
console.log('Component unmounted');
};
}, []);
export default MyComponent;
useRef는 일반적으로 ref 속성으로 사용되는 객체를 생성합니다. 이 객체는 current 프로퍼티를 가지고 있는데, 이 프로퍼티를 통해 저장된 값을 읽거나 업데이트 할 수 있습니다.
useRef 는 상태를 업데이트할 때마다 컴포넌트를 다시 렌더링하지 않습니다.
DOM 노드에 접근하기
기본값 : const 변수명 = useRef();
import { useRef } from 'react';
const myComponent = () => {
const inputRef = useRef(null);
const handleClick = () => {
inputRef.current.focus();
}
return (
<div>
<input type="text" ref={inputRef} />
<button onClick={handleClick}>focus</button>
</div>
)
}
이전 상태에 접근하기
const { useRef, useState } = 'react';
const MyComponent = () => {
const [value, setValue] = useState('');
const valueRef = useRef('');
const handleChange = (event) => {
const {value} = event.target;
valueRef.current = value;
setValue(value);
}
const handleSubmit = (event) => {
event.preventDefault();
console.log(valueRef.current)
console.log(value)
}
return (
<div>
<form onSubmit={handleSubmit}>
<input type="text" value={value} onChange={handleChange}/>
<button type="submit">제출</button>
</form>
</div>
)
}
export default MyComponent
왜 useCallback 을 사용하는가?
컴포넌트 내에서 함수를 생성하고 있다면 새로운 함수가 만들어집니다.
예를 들어 Counter 컴포넌트 안에 increament 함수들은 컴포넌트가 리렌더링 될 때마다 새로 만들어지게 됩니다.
아니면 하위 컴포넌트로 함수를 넘겨줄때 함수를 포함하고 있는 컴포넌트가 리 렌더링 될 때마다 자식 컴포넌트도 함수가 새롭게 만들어지니 계속 리렌더링 됩니다.
import React, { useState, useCallback } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
const handleIncrement = useCallback(() => {
setCount(count + 1);
}, [count]);
return (
<div>
<p>Count: {count}</p>
<button onClick={handleIncrement}>Increment</button>
</div>
);
}
export default MyComponent;
useCallback 적용은 useCallback 안에 콜백함수와 의존성 배열을 순서대로 넣어주면 된다.
useCallback으로 인해서 의존성 배열에 추가해준 state 혹은 props 가 변하지 않는 다면 함수는 새로 생성되지 않는다.
의존성 배열에 마우것도 없다면 컴포넌트가 최초 렌더링 시에만 함수가 생성되며 그 이후에는 동일한 참조값을 사용하는 함수가 된다.
여기서 메모이제이션이란 비용이 많이 드는 함수 호출의 결과를 저장하고 동일한 입력이 다시 발생할 때 캐시된 결과를 반환하여 컴퓨터 프로그램의 속도를 높이는 데 주로 사용되는 최적화 기술 입니다.
useMemo Hook 은 두 개의 매개변수를 전달받습니다. 첫 번째 매개변수로는 메모이제이션 대상이 되는 함수를 전달하고, 두 번째 매개변수로는 의존성(dependency) 배열을 전달합니다. 의존성 배열에 포함된 값이 변경될 때마다, 메모이제이션된 값을 다시 계산합니다.
하지만 훅을 남용하면, 오히려 성능이 저하될 수 있습니다.
기본값 : useMemo(() => {}, [])
import React, { useState, useMemo } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
const factorial = useMemo(() => {
function calculateFactorial(n) {
if (n <= 1) {
return 1;
} else {
return n * calculateFactorial(n - 1);
}
}
console.log('Calculating factorial...');
return calculateFactorial(count);
}, [count]);
const handleIncrement = () => {
setCount((prevCount) => prevCount + 1);
};
return (
<div>
<p>Count: {count}</p>
<p>Factorial: {factorial}</p>
<button onClick={handleIncrement}>Increment</button>
</div>
);
}
export default MyComponent;
이 함수는 Hook 이 아니지만 Hook 이랑 많이 쓰이기 때문에 추가했습니다.
React.memo는 컴포넌트를 렌더링할 때 프롭스(props)가 변경되었는지 비교하여, 변경되지 않았다면 이전에 렌더링된 결과를 재사용합니다. 이를 통해, 컴포넌트의 재렌더링을 방지하고, 성능을 최적화할 수 있습니다.
import React from 'react';
const MyComponent = React.memo((props) => {
// props를 이용한 컴포넌트 구현
});
export default MyComponent;
또는
import React from 'react';
const MyComponent = (props) => {
// props를 이용한 컴포넌트 구현
};
export default React.memo(MyComponent);