contextApi(useContext)
useContext란?
contextApi를 사용하면 하위 컴포넌트에서도 상위 컴포넌트에서 전달하는 값을 props를 통하지 않고서 전달 받을 수 있다. 동일한 context를 넘겨 받은 인자를 통해서 공유가 가능하다. 이 함수를 통해서 state값과 이를 업데이트 해주는 함수를 컴포넌트끼리 공유 할 수 있다. props drilling을 방지 가능하다.
props drilling
prop drilling이란?
컴포넌트의 deps가 깊어질수록 자식 컴포넌트에 넘겨지는 props가 많아진다. props가 많아질수록 props 추적이 어려워지기 때문에 관리가 힘들어지는 것을 말한다.
(props drilling의 예시)
useContext를 사용한 예
만약 contextApi를 사용하게 된다면 앱 안에서 전역적으로 사용되는 데이터들을 여러 컴포넌트끼리 쉽게 공유할 수 있는 방법을 제공해준다. props로 내려주지 않고, 동일한 context를 넘겨 받은 인자를 통해서 공유가 가능하다.
하지만 이런 Context를 남발한다면
- 불필요한 리렌더링: useContext를 이용하여 많은 컴포넌트가 같은 컨텍스트를 사용하는 경우, 해당 컨텍스트가 변경될 때마다 모든 컴포넌트가 리렌더링될 수 있다. 이는 성능 저하로 이어질 수 있다.
- 컴포넌트 결합도 증가: useContext를 남발하면 컴포넌트 간의 결합도가 높아질 수 있다. 컴포넌트들이 컨텍스트에 강하게 의존하면 재사용성이 떨어지고, 컨텍스트를 변경할 때마다 관련된 많은 컴포넌트를 수정해야 할 수 있다.
- 디버깅의 어려움: 많은 컴포넌트가 같은 컨텍스트를 사용하는 경우, 컨텍스트 값의 변경이 어떤 컴포넌트에 영향을 미치는지 파악하기 어려울 수 있다.(스택트레이스 or 콜스택)
따라서 상황에 따라 contextApi를 사용하는 것이 좋다.
contextApi의 리렌더링
contextApi는 props drilling을 막기 위한 수단일 뿐이며, 내부의 state가 변경되면, 하위 컴포넌트들이 전부 렌더링되는, 리액트 컴포넌트의 룰을 벗어나지 않는다.
TestContextProvider로 감싸져있는 page에서하위 컴포넌트로 page1 → page2 → page3 로 이어지는 컴포넌트가 있다.
스크린샷 2023-07-20 오후 9.42.45
Page1
만약 page1에서 number를 증가시키는 함수를 실행 시킨다면 page1에 있는 하위 컴포넌트가 모두 리렌더링 된다.
해결 방법
1. 리액트에서 제공해주는 최적화 방법사용(React.memo, useMemo)
React.memo? useMemo ?
각각 다른 목적과 사용 사례가 있기 때문에 어떤 것을 사용할지는 상황에 따라 다르다.
- React.memo
- 만약 컴포넌트가 같은 props를 받을 경우 같은 결과를 렌더링 한다면 React.memo를 사용하여 불필요한 렌더링을 방지 할수 있다. 즉, 컴포넌트에 같은 props가 들어온다면 리액트는 컴포넌트 렌더링 과정을 스킵하고 마지막에 렌더링된 결과를 재사용한다.
- React.memo는 오직 props가 변경됐는지 아닌지만 체크한다. 만약 React.memo에 감싸진 함수형 컴포넌트가 함수 내부에서 useState나 useContext같은 훅을 사용하고 있다면, state나 context가 변경될 때마다 리렌더링된다.
- React.memo는 얕은 비교로 리렌더링을 방지하기 때문에 컴포넌트의 Props의 변화를 탐지하기 어려울 수 있다. 예를 들어, 부모 컴포넌트에서 동일한 값을 가진 객체를 생성하여 자식 컴포넌트에 전달하더라도, 객체의 참조는 다르기 때문에 React.memo는 새로운 Props를 받은 것으로 간주하여 리렌더링을 발생시킨다. 만약 비교방식을 커스텀하고 싶다면 아래 코드처럼 비교함수를 React.memo의 두번째 인자로 넣어주면 된다.
function MyComponent(props) {
}
function areEqual(prevProps, nextProps) {
}
export default React.memo(MyComponent, areEqual);
- useMemo
- useMemo는 메모라이즈된 값을 return하는 hook이다.
- 계산 비용이 큰 연산의 결과를 캐싱하고 재사용하는 데 사용된다. 즉, 특정 값을 메모이제이션하여 동일한 입력에 대해 불필요한 계산을 피할 수 있다.
- 함수형 컴포넌트 내부에서 특정 값을 계산하고 그 값을 기억하며, 의존성 배열이 변경되지 않는 한 이전에 계산된 값을 반환합니다.
- 주로 계산 비용이 큰 연산이나 렌더링에 많은 리소스가 소비되는 연산을 최적화하는 데 사용된다.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
- 차이점
- React.memo는 HOC, useMemo는 hook이다.
- React.memo는 HOC이기 때문에 클래스형 컴포넌트, 함수형 컴포넌트 모두 사용 가능하지만, useMemo는 hook이기 때문에 오직 함수형 컴포넌트 안에서만 사용 가능하다.
번외. useCallback
useCallback이란?
- useCallBack은 useMemo와 React.memo와 같이 렌더링 성능을 향상시키기 위한 리액트 hook이다.
- 함수형 컴포넌트 내에서 콜백함수를 메모하여 이전에 계산된 값을 의존성 배열에 포함된 값이 변경되지 않는 한 같은 콜백 함수를 재사용한다.
- 주로 자식 컴포넌트에 전달되는 콜백 함수들을 최적화할 때 사용한다.
const memoizedCallback = useCallback(callback, dependencies);
useMemo와 차이점
- useCallBack은 주로 콜백 함수의 메모이제이션을 위해 사용되고, useMemo는 주로 계산 결과의 메모이제이션을 위해 사용된다.
- useCallBack은 콜백함수의 재생성 방지, 함수를 반환함
- useMemo는 계산된 결과값을 캐싱, 값을 반환함.
- 둘다 의존성 배열을 받음. 만약 빈배열([ ])일시 최초 렌더링 됐을 때의 값을 캐싱
ContextApi 와 redux의 차이점
- ContextApi는 엄밀히 말하자면 상태관리를 하지 않는다.
- 상태관리는 Hook을 통해 관리한다.
- 단순 값을 전달하는 파이프와 같다. 사용하는 주요 목적은 prop-drilling 을 피하는 것이다.
- redux는 애플리케이션 전체에 대한 상태 중앙 저장소 역할을 한다.
- action이라는 이벤트를 사용하여 애플리케이션의 상태를 예측 가능한 방식으로 업데이트 하기 위한 패턴 또는 라이브러리이다.
언제 contextApi와 redux를 사용할까?
- 단순 prop-drilling 을 피하는 것이 목적이라면 Context 를 사용
- 적당히 복잡한 컴포넌트가 있거나 외부 라이브러리를 사용하고 싶지 않다면 Context + useReducer 를 사용
- 특정 구성 요소만 re-render 시키거나, 사이드이펙트를 줄이기 위해 더 강력한 기능이 필요하다면 Redux + React-Redux를 사용
Context API vs Redux
ContextApi + useReducer
1. useReducer란?
- React에서 제공해주는 Hook으로 useState보다 더 다양한 컴포넌트 상황에 따라 다양한 상태를 다른 값으로 업데이트해 주고 싶을 때 사용하는 Hook이다. state의 개수를 대폭 줄일 수 있다.
- 리듀서 함수는 현재 상태(state)와 액션(action)을 받아서 새로운 상태를 반환하는 함수로 작성된다. 액션은 상태를 변경하는 데에 사용되는 객체이며, 보통 type 속성을 가지고 있다.
useReducer를 통해 상태와 디스패치 함수를 생성
리듀서 함수와 초기 상태를 전달하고, 리듀서 함수가 반환하는 상태와 디스패치 함수를 사용하여 상태를 업데이트할 수 있다. 액션을 디스패치하여 상태를 변경하고, 변경된 상태를 화면에 렌더링한다.
useReducer는 상태와 관련된 복잡한 로직을 리듀서 함수로 분리하여 코드를 관리하기 쉽게 해준다. 상태가 많고 복잡한 상태 변화를 다룰 때 useReducer를 사용하면 코드를 구조화하고 관리하기 용이해진다. useState는 간단한 상태 관리에 적합하며, 상태 관리가 좀 더 복잡해지면 useReducer를 고려할 수 있다.
2.ContextApi와 같이 사용하기
출처 - 별코딩
이런 유용한 정보를 나눠주셔서 감사합니다.