
usestate는 함수형 컴포넌트에서 상태를 관리하는 데 사용되는 Hook이다. 컴포넌트 내부에서 개별적으로 상태를 선언하고 업데이트할 수 있다.
const [state, setState] = useState(초기값);
//state의 형태에 맞추어 초기값을 선언한다
const [array, setArray] = useState([]);
const [object, setObject] = useState({});
//state 값을 업데이트 하는 법
setState(바꿀값);
React는 state가 변경될 때 컴포넌트를 렌더링 시키는데, state가 2개 이상이여도 Batching이란 것 때문에 렌더링은 최종적으로 한번만 진행한다.
const [count, setCount] = useState(0);
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
console.log(count);
// 실행 결과 count = 1
총 3번의 연산으로 인해 count의 결과값을 3으로 예상하겠지만, 렌더링은 한번만 되기 때문에 count의 값은 계속 1이다.
이 때문에 React는 setState에 값을 직접적으로 넣어서 변경하기 보다는 콜백 함수로 넣어 주기를 권장한다.
setState()의 콜백함수는 초기값인 prevState를 첫번째 인자로 제공하며, return 되는 값이 setState()의 최종 값이 된다.
const [count, setCount] = useState(0);
setCount(prevState => prevState + 1);
setCount(prevState => prevState + 1);
setCount(prevState => prevState + 1);
console.log(count);
//실행 결과 count = 3
또한, setState는 배열이나 객체를 push, splice, sort과 같이 배열을 직접적으로 변경하는 메소드는 사용할 수 없다. setState는 자동적으로 이전 객체와 현재 객체를 합쳐주지 않기 때문에 spread operator로 destructuring 한 후에 새로운 속성과 값을 업데이트 해줘야 한다.
// 객체의 경우
setState(prev => {
return {
...prev,
name : value
}
};
// 배열의 경우
setState(prev => [...prev, value]);
여기까지는 '추가'의 방법이고, '제거'하는 방법은 배열에 filter() 메서드를 사용한다.
const [numbers, setNumbers] = useState([1, 2, 3, 4, 5]);
setNumbers(prev => {
return prev.filter(number => {
return number < 4
});
});
console.log(numbers);
//실행 결과 numbers = [1, 2, 3]
" Too many re-renders. React limits the number of renders to prevent an infinite loop."
" 너무 많은 렌더링으로 무한 루프에 빠져 버렸다 "
state를 사용할 때는 재렌더링으로 인한 무한 루프에 빠지는 것을 주의해야 한다.
const [state, setState] = useState(1);
setState(2);
무심코 이런 코드를 작성을 했다면 프로그램은 무한 루프에 빠져버리게 된다.
state는 값이 바뀔 때 마다 컴포넌트를 재렌더링 시킨다. 때문에 setState로 값을 바꿈과 동시에 컴포넌트는 제렌더링이 되고, 처음으로 돌아가 다시 state의 값을 바꾸기를 반복하기 때문에 무한 루프에 빠지는 것이다.
const [state, setState] = useState(1);
const clickHandler = () => {
setState(2);
}
return <button onClick={clickHandler}> Click </button>
무한루프를 해결하기 위해서는 이처럼 이벤트 핸들러로 함수로 전달 하거나 useEffect() 등을 사용하여 state 변경에 조건을 걸어 주는 것 이다.
useEffect는 컴포넌트가 마운트되거나 재렌더링, 언마운트 될 때 특정 작업을 비동기로 실행할 때 사용되는 Hook이다.
//useEffect 사용법
useEffect(() => { 실행 함수... }, [Dependency Array]);
useEffect()의 첫번째 인자로 콜백함수를 넣어 렌더링 될 때 실행할 함수를 입력한다.
useEffect()의 두번째 인자로 의존성 배열(dependency array)을 입력한다. 의존성 배열에 포함된 값이 변경되면 함수는 다시 실행됩니다.
Dependency : useEffect의 dependency에는 컴포넌트의 state, props, 또는 외부에서 선언한 변수 등, useEffect 함수가 실행될 때 고려해야 할 값의 목록을 넣을 수 있다.
//두번째 인자를 받지 않고
useEffect(() => { 실행 함수... });
dependency 없이 함수만 실행시킬 경우, 렌더링이 될 때 마다 함수를 실행시킨다.
//두번째 인자로 빈 배열
useEffect(() => { 실행 함수... }, []);
dependency가 빈 배열일 때는 컴포넌트가 마운트 될때, 한번 함수를 실행시킨다.
//두번째 인자로 의존할 값을 받음
useEffect(() => { 실행 함수... }, [dep1, dep2, dep3]);
dependency로 받은 변수의 값이 변경될 때 마다 함수를 실행 시킨다.
//실행 함수의 return() 값으로 callback 함수
useEffect(() => {
//실행 함수..
const timer = setInterval(()=>{}, 1000);
return(() => {
//cleanup...
clearInterval(timer);
})
});
cleanup함수는 언마운트, 컴포넌트가 사라질 때 호출되는 부분으로 메모리누수를 방지하여 메모리 관리를 하거나 컴포넌트가 사라질 때, 수행할 작업들을 추가하기 위해 사용한다.
useMemo는 함수의 결과를 메모리에 저장하고(Memoization), 함수의 입력값이 변경될 때만 함수를 다시 호출해 불필요한 호출을 막는 Hook.
기본적으로 리액트의 함수형 컴포넌트는 함수이기 때문에 useState등으로 인해 컴포넌트가 재렌더링 되면 변수들이 초기화 되고, 컴포넌트 안에 함수들도 불필요하게 호출된다.
const memoValue = useMemo(() => {
return 호출할 함수
}, [Dependency Array])
useMemo() 의 콜백함수의 return 값을 memoization 한다.
useEffect 와 마찬가지로 'Dependency array'에 의존성 값이 변할 때만 함수를 호출한다.
의존성 값이 변경되지 않는다면 Memoization 된 값을 사용한다.
useCallback은 함수의 자체를 메모리에 저장하여(Memoization) 필요할 때마다 함수를 재생성하여 사용할 수 있게 하는 Hook.
const memoCallback = useCallback(() => {
//함수 코드
}, [Dependency Array])
useMemo 는 함수의 결과값을 메모제이션,useCallback 은 함수 자체를 메모제이션.
useRef는current를 속성으로 갖는 객체이며,
저장공간 또는 DOM요소에 접근하기 위해 사용되는 Hook.
// useRef 초기화
const ref = useRef(초기값);
//useRef 사용하기
ref.current = 바꿀값;
useState와 다르게 변수 값이 변경되어도 컴포넌트를 리렌더링 시키지 않는다.
일반 변수와 다른 점은 컴포넌트가 리렌더링 되는 순간 모든 변수들은 초기화 되지만 useRef는 useState와 같이 컴포넌트가 언마운팅 될 때 까지 값을 저장해 놓는다. (= 리렌더링 되어도 동일한 객체를 제공)
useState는 리렌더링 시킬 때 한번에 몰아서 값을 업데이트하려는 성질을 갖고 있지만, useRef는 값을 즉시 업데이트한다.
const App = () => {
// inmputRef를 useRef()로 초기화 시킨다
const inputRef = useRef();
return (
// ref의 값으로 DOM요소에 접근할 수 있게 만들어 준다
<input ref={inputRef}/>
)
}
useRef()로 초기화 시켜 컴포넌트의 ref 값으로 데이터 바인딩을 시켜주면 DOM 요소에 접근할 수 있게 한다.
위 코드에서의 inputRef는 useRef Hook이 반환하는 객체가 되며, input 요소를 참조하게 된다. (inputRef.current.value 등으로 접근 가능)
useContext는 React 컴포넌트 트리 전역에서 데이터를 전달할 수 있게 해주는 Hook이다.props로 넘겨줘야하는 prop drilling 현상의 비효율적인 현상을 막을 수 있다.
//AnyContext.js 파일
import { createContext } from "react";
export const AnyContext = createContext();
Redux의 store처럼 전역으로 데이터를 관리해줄 context 파일을 생성한다.
context 컴포넌트를 export 해준다.
// 최상위 컴포넌트 파일
import { AnyContext } from `./anyContext.js`;
const App = () => {
let food = "chicken";
let price = 18000;
return (
<AnyContext.Provider value={{food, price}}>
<Children />
</AnyContext.Provider>
)
};
context.Provider 컴포넌트로 감싸 준다.
context.Provider 컴포넌트의 value prop으로 값을 넣어 주면 Children 컴포넌트부터 하위 컴포넌트 전역까지 value의 값을 받을 수 있다.
import { useContext } from 'react';
import { AnyContext } from `./anyContext.js`;
const Consumer = () => {
const {food, price} = useContext(AnyContext);
return (
<h1>{food}은 {price}원입니다!</h1>
)
}
// Chicken은 18000원입니다!
사용하는 컴포넌트는 useContext와 생성한 anyContext를 import한다.
useContext()를 호출해 변수에 저장해 사용하면 된다.
useContext() 의 매개변수로 생성한 context를 넣어주면 된다.
Custom Hooks는 함수형 컴포넌트에서 재사용 가능한 코드를 작성할 수 있는 Hook이다. 상태 관리를 단순화하며, 코드의 가독성을 향상시킨다.
//커스텀 훅스 파일
const useHooks = () => {
// 재사용할 코드
const [state1, setState1] = useState(1);
const [state2, setState2] = useState(2);
setState1(2);
setState2(3);
return [state1, state2]
}
Custom Hooks의 컴포넌트 명은 'use'로 시작한다.
재사용할 값을 return 해준다.
return 값은 JSX 문법이 아닌 객체 또는 배열로 리턴한다.
React 내장된 훅을 사용할 수 있다.
//커스텀 훅스를 사용하는 파일
import useHooks from ./hooks.js
const App = () => {
// Custom Hooks 리턴 값을 가져온다
const [state1, state2] = useHooks();
}
import한 뒤, useHooks()를 호출하여 return된 것을 변수로 저장하면 된다.