728x90
반응형
📌 useContext 훅
React 컴포넌트는 부모에서 자식으로 props를 통해 데이터를 전달해야한다.
이때, 컴포넌트의 수가 많아지고 트리 구조가 복잡해지면
단계별로 데이터를 전달해야하는 리액트에서 코드는 굉장히 복잡해지기 마련이다.
중간에 코드가 바뀌게 된다면 일일히 다 찾아 바꿔야하기도 하고,
해당 데이터가 필요하지 않은 컴포넌트에도 데이터가 전달되어 코드가 지저분해지기도 한다.
이런 문제를 해결하기 위해 우리는 useContext 를 사용한다.
전역적으로 사용되는 데이터들을 공유해
최상단 컴포넌트에서 최하단 컴포넌트까지 데이터 전달을 손쉽게 할 수 있다.
ex) 유저 정보, 테마, 언어, ...
useContext() 훅은 리액트에서 상태를 전역적(globally)으로 사용할 수 있도록 해줍니다.
useState()로 생성한 상태는 기본적으로 지역적(locally)이지만,
useContext()와 함께 사용하면 상태를 전역적으로 사용할 수 있어집니다.
🔎 useState만 사용해서 앱 컴포넌트에 전체에 theme 상태를 공유하려고 하면
모든 컴포넌트마다 props로 theme 상태를 지정해 내려줘야하는 큰 불편함이 생기게 됩니다.
🔎 useContext와 함께
useState를 사용하면 상태를 전역적으로 관리하므로
필요한 곳에서만 useContext 함수로 호출해서 사용
📌 useContext 구성요소
- 컨텍스트 생성(전역공유) ➡️ createContext : 컨텍스트 객체 생성
- 부모 컴포넌트 ➡️ Provider : 생성한 컨텍스트를 하위 컴포넌트에게 전달
- 자식 컴포넌트 ➡️ useContext(Context); : 해당 컨텍스트의 현재 상태값 가져옴
✅ createContext() - 컨텍스트 생성 (전역 공유)
- React.createContext(defaultValue);
- 컨텍스트 객체를 생성하여 전역 상태를 관리
- createContext() 함수 호출 시 Provider와 Consumer 반환
- Provider : 생성한 context를 하위 컴포넌트에게 전달하는 역할
- Consumer : context의 변화를 감시하는 컴포넌트
- 초기값 : Provider를 사용하지 않았을 때 적용될 초기값
import React, { createContext } from 'react';
export const UserContext = React.createContext(초기값);
✅ Provider - 컨텍스트 값 제공, 하위 컴포넌트에게 값 전달
- Context.Provider
컨텍스트의 값을 제공하고, 하위 컴포넌트들에게 해당 값 전달
Provider로 감싸진 모든 하위 컴포넌트에서 사용가능 (전역 공유) - value={prop}
Provider의 value prop을 통해 컨텍스트에 전달할 데이터를 설정 - 객체 형식의 데이터는 value={{data}} 형태로 전달
- 첫 번째 {} : JSX에서 자바스크립트 표현식을 사용
- 두 번째 {} : 자바스크립트 객체를 만들기 위한 중괄호
<UserContext.Provider value={ 공유할 데이터 } />
<하위컴포넌트 />
</UserContext.Provider>
✅ useContext(Context) - 현재 상태값 가져오기
- 컨텍스트의 현재 상태값을 가져온다.
- createContext를 통해 생성된 Context 객체를 파라미터로 넘겨받는다.
- 이 객체는 Context.Provider를 통해 제공된 값을 읽어옵니다.
import React, { useContext } from 'react';
import { UserContext } from './context'; // 컨텍스트 객체 가져오기
const ChildComponent: React.FC = () => {
const context = useContext(UserContext);
if (context === undefined) {
throw new Error('ChildComponent must be used within a UserProvider');
}
return (
<div>
// 컨텍스트에서 가져온 값 출력
유저 아이디 : {context.userID}
</div>
);
};
export default ChildComponent;
✏️ useContext 사용해보기
📜 context.tsx - 컨텍스트 제공자 (UserProvider) 정의
- 역할 : 컨텍스트와 그에 관련된 타입, 초기값, Provider 정의
- 내용
- 컨텍스트 객체 생성 (createContext)
- Provider 컴포넌트 정의
UserProviderProps | UserProvider 컴포넌트의 props 타입 정의 children : ReactNode; UserProvider가 받는 children 프로퍼티의 타입을 정의합니다. ReactNode는 모든 리액트 요소(자식 컴포넌트, 텍스트, 프래그먼트 등)를 포함하는 타입입니다. |
FC<UserProviderProps> | FC (Functional Component) 리액트의 함수형 컴포넌트 타입 정의 React.FC와 FC는 동일한 타입 React.FC<UserProviderProps> FC<UserProviderProps> 타입을 사용하면 UserProvider가 UserProviderProps 타입의 props를 받는 함수형 컴포넌트로 정의 |
{children} | UserProvider가 자신의 자식 컴포넌트를 렌더링합니다. Provider 내부에서 {children}은 UserProvider로 감싸진 모든 하위 컴포넌트를 렌더링하는 역할을 합니다. |
import React, { createContext, useState, ReactNode, FC } from 'react';
// ▶ 컨텍스트 타입 정의
export interface UserContextType {
userID: string;
setUserID: (id: string) => void; // setUserID 함수의 타입 정의
}
// ▶ UserContext 컨텍스트 생성(초기값 undefined)
// → 자식 컴포넌트에서 useContext(UserContext)를 호출하면,
// UserContext.Provider가 제공하는 value 객체를 사용할 수 있습니다.
export const UserContext = createContext<UserContextType | undefined>(undefined);
// ▶ UserProviderProps: props의 구조를 정의
interface UserProviderProps {
// Provider의 자식 요소의 타입 정의(ReactNode)
children: ReactNode; // 리액트 노드: JSX 요소, 문자열 등 렌더링 가능한 모든 요소
}
// ▶ UserProvider 컴포넌트
// → 컨텍스트를 정의하고, 상태를 설정하며, 상태를 자식 컴포넌트에 제공
// → userID와 setUserID를 상태 가지고 있다.
// UserContext.Provider를 통해 전달
// → UserProvider: FC<UserProviderProps> 타입의 함수형 컴포넌트
export const UserProvider: FC<UserProviderProps> = ({ children }) => {
// ● 상태 초기값 설정
// → 상태 정의: userID와 이를 변경하는 함수
const [userID, setUserID] = useState<string>('');
// ● 컨텍스트에서 제공할 값
// → userID: useState로 정의된 상태 변수의 현재 값
// → setUserID: useState로 정의된 상태를 변경하는 함수
const value: UserContextType = { userID, setUserID };
// ● 컨텍스트 제공
// → UserContext.Provider를 사용하여, 상태와 상태 업데이트 함수를 value로 설정
// UserProvider로 감싼 자식 컴포넌트들은 이 value를 사용할 수 있다.
return (
<UserContext.Provider value={value}>
{children} {/* 전달받은 자식 요소들을 렌더링 */}
</UserContext.Provider>
);
};
📜 App.tsx - 루트 컴포넌트 정의하고 렌더링
- 역할
애플리케이션의 루트 컴포넌트를 정의하고,
Provider로 애플리케이션을 감싸서 하위 컴포넌트들에게 컨텍스트를 제공하는 역할 - 내용
- Provider를 사용하여 애플리케이션을 감쌈
- 하위 컴포넌트를 렌더링
<UserProvider> · · · </UserProvider> |
UserProvider로 애플리케이션을 감싸 ChildComponent와 같은 하위 컴포넌트들이 컨텍스트 값을 사용할 수 있도록 합니다. |
import React from 'react';
import ReactDOM from 'react-dom';
import { UserProvider } from './context'; // UserProvider 가져오기
import ChildComponent from './ChildComponent'; // useContext를 사용하는 컴포넌트
// ▶ App: UserProvider를 사용하여 자식 컴포넌트를 전달하는 컴포넌트
export const App: React.FC = () => {
return (
<UserProvider>
<ChildComponent /> {/* UserProvider로 감싸서 자식 컴포넌트가 컨텍스트를 사용 가능 */}
</UserProvider>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
📜 ChildComponent.tsx - 컨텍스트 데이터를 사용하는 컴포넌트
- 역할 : useContext를 사용하여 컨텍스트 값을 가져오고 이를 화면에 출력
- 내용
- useContext를 통해 컨텍스트 값 읽기
- 값을 화면에 표시
import React, { useContext } from 'react';
import { UserContext } from './context'; // 컨텍스트 객체 가져오기
const ChildComponent: React.FC = () => {
// ▶ useContext를 사용하여 컨텍스트 값을 가져옴
// → useContext(UserContext)는 현재 UserContext.Provider가 제공한 값을 반환
// 자식 컴포넌트는 useContext(UserContext)를 통해,
// UserProvider에서 제공한 value를 가져옵니다.
// → value에는 상태(userID)와 상태를 변경하는 함수(setUserID)가 포함
// 자식 컴포넌트는 이 값을 사용하여 상태를 읽고, 변경할 수 있다.
const context = useContext(UserContext);
// ▶ 컨텍스트가 제공되지 않았다면 에러 발생
if (context === undefined) {
throw new Error('ChildComponent must be used within a UserProvider');
}
// ▶ userID를 변경하는 함수
const changeUserID = () => {
context.setUserID('소현'); // 예시로 '소현'으로 변경
};
return (
<div>
유저 아이디 : {context.userID} {/* 컨텍스트에서 가져온 값 출력 */}
<button onClick={changeUserID}>Change User ID to '소현'</button> {/* 버튼 클릭 시 userID 변경 */}
</div>
);
};
export default ChildComponent;
728x90
반응형
'📌 Front End > └ React' 카테고리의 다른 글
[React] 리액트 훅 - useMemo, useCallback(메모이제이션 값, 함수 반환) (0) | 2024.08.30 |
---|---|
[React] 리액트 훅 - useEffect(조건부 실행, 자원 정리) (0) | 2024.08.30 |
[React] 리액트 훅 - useReducer(관리 코드 컴포넌트 외부 분리) (0) | 2024.08.28 |
[React] 리액트 이벤트 처리 - 핸들러, 컴포넌트 상태(useState), 단방향 바인딩 (0) | 2024.08.26 |
[React] 리액트 내장 컴포넌트(Fragment, Profiler, StrictMode, Suspense, lazy) (0) | 2024.08.21 |