숫자를 세는 count를 useState로 작성하면 아래와 같다.
const [count, setCount] = useState(0);
버튼을 누를 때 숫자가 3씩 증가되는 onClick 함수를 작성할 때 함수 안에
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
이런 방식을 이용하려고 한다면, 리렌더링 될 때마다 count가 3씩 더해질까?
❗ 답은 "안된다" 이다.
react에서는 값을 효율적으로 업데이트 하기 위해서 업데이트 하려는 것을 한번에 모아서 처리하려고 한다.
따라서, setCount(count + 1)이 3번 실행되는게 아니라 한번에 모아서 한번만 실행되기 때문에 1만 증가하는 것이다.
반면에
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
이렇게 작성하게 된다면
prev 값에 1이 더해진 값이 다시 prev로 들어가게 되면서 증가된 값이 다음 setCount로 return되기 때문에 원하는대로 3이 증가가 된다.
따라서 반복적으로 set을 써야할 때 return한 값을 넘겨주는 식으로 써야 원하는대로 코드가 작성된다.
배치 업데이트
react가 더 나은 성능 개선을 위해, 여러개의 state 업데이트를 한번의 리렌더링으로 묶어서 진행하는 것을 말한다.
input value를 얻기 위해 onChange에서 setValue를 쓴다면, 값이 입력될 때마다 리렌더링이 되기 때문에 onChange에서 setValue를 하는 것은 리소스 낭비가 크다고 할 수 있다.
의존성 배열 : 배열 안의 값이 바뀔 때만 useEffect를 실행
//모든 state 값이 변경 될 때 마다 실행
useEffect(()=>{
console.log('hi');
})
//최초 한 번만 실행
useEffect(()=>{
console.log('hi');
},[])
//count값이 바뀔 때만 실행
useEffect(()=>{
console.log('hi');
},[count])
useEffect의 생애주기
useEffect(() => {
console.log("mount");
return () => {
console.log("unmount");
};
}, []);
const ref = useRef("초기값");
console.log(ref); // 초기값
ref.current = "바꾼 값";
console.log(ref); //바꾼 값
useRef는 useState와 마찬가지로 값을 저장하는 것이지만, useRef의 값이 바뀐다고 렌더링이 일어나지 않는다는 게 가장 큰 차이점이다.
redux를 배울 때 중요한 개념이다.
react의 데이터 흐름은 일반적으로 부모 컨포넌트 → 자식 컴포넌트이다.
하지만 컴포넌트가 늘어나면 계속해서 props를 넘겨줘야하는 “props drilling 현상이 일어나게 된다.
특정 영역 안에서 state를 공유하는 개념이다.
useContext를 이용해서 전체 데이터 관리를 하게 한다.
전역 데이터의 개념.
Context API 사용하는 방법
- 컴포넌트
조부모님 > 부모님 > 본인- context 파일
FamilyContext.js 안에 context를 생성
import { createContext } from 'react';
//context를 생성
export const FamilyContext = createContext(null);
const GrandParents = () => {
const houseName = "스파르타";
const pocketMoney = 10000;
return (
<FamilyContext.Provider //provider로 하위 컴포넌트에 전달
value={{
houseName,
pocketMoney,
}}
>
<Parents />
</FamilyContext.Provider>
)
}
const Child = () => {
//useContext를 이용해 FamilyContext의 값을 구조분해 할당해서 받음
const {houseName, pocketMoney} = useContext(FamilyContext);
return (
<div>
우리 집 이름은 {houseName} 이고
용돈을 {pocketMoney} 만큼 받았어요
</div>
)
}
이렇게 전역으로 데이터를 관리하면, parents 컴포넌트를 거치지 않고 child 컴포넌트로 값을 전달할 수 있다.
하지만 이렇게 전역으로 관리하게 되면 생기는 문제점이 있는데, Provider로 관리한 데이터 값이 바뀌게 된다면 useContext를 사용하고 있는 모든 컴포넌트가 리렌더링 되는게 문제가 된다.