: 같은 문맥( 목적 ) 아래에 있는 컴포넌트 그룹에 데이터를 공급하는 기능
사용 이유
리액트 컴포넌트 계층 구조에서 컴포넌트 간에 값을 전달할 때 발생하는 Props Drilling 문제를 해결하기 위해 사용됩니다.
→ Context 이용 시 단계마다 일일이 Props를 전달하지 않고도 컴포넌트 트리 전역에 데이터를 공급할 수 있어 Props Drilling 문제를 간단하게 해결할 수 있습니다.
: Context를 만들고 다루는 리액트 기능으로 createContext, Context.Provider 등이 있습니다.
Context 만들기
import React from "react";
const MyContext = React.createContext(defaultValue);
Context에 데이터 공급하고 사용하기
import React from "react";
const MyContext = React.createContext(defaultValue);
function App() {
const data = "data";
return (
<div>
<Header />
<MyContext.Provider value={data}>
<Body />
</MyContext.Provider>
<div>
);
}
function Main() {
const data = useContext(MyContext);
( ... )
}
≫ 정리하면 createContext를 이용해 Context를 만들고, 값을 공급할 컴포넌트를 Context.Provider로 감싼다음 함수 useContext를 호출해 Context가 공급하는 값을 불러와 사용합니다.
리팩토링
: 사용자에게 제공하는 기능은 변경하지 않으면서 내부 구조를 개선하는 작업
어떻게 Context 적용할지 생각해보기
TodoItem 컴포넌트가 Props를 사용하려면 TodoList 컴포넌트를 거쳐서 전달해야 해 Props Drilling 문제가 발생합니다.
→ TodoContext 생성 후 TodoContext.Provider 아래에 TodoEditor, TodoList, TodoItem 컴포넌트 배치
import React, { useCallback, useReducer, useRef } from "react";
( ... )
const TodoContext = React.createContext();
return (
<div className="App">
<Header />
<TodoContext.Provider value={{ todo, onCreate, onUpdate, onDelete }}>
<TodoEditor />
<TodoList />
</TodoContext.Provider>
</div>
);
}
export default App;
const TodoList = ({ todo, onUpdate, onDelete }) => {
( ... )
}
TodoList.defaultProps = {
todo: [],
};
export default TodoList;
App.js에 선언한 TodoContext를 다른 파일에서 불러오기 위해선 export로 내보내야 합니다.
( ... )
export const TodoContext = React.createContext();
( ... )
TodoList 컴포넌트
import { useContext, useMemo, useState } from "react";
import { TodoContext } from "../App";
( ... )
const TodoList = () => {
const { todo } = useContext(TodoContext);
( ... )
return (
<div className="TodoList">
( ... )
<div className="list_wrapper">
{getSearchResult().map((it) => (
<TodoItem
key={it.id}
{...it}
/>
))}
</div>
</div>
);
};
export default TodoList;
≫ 나머지 다른 컴포넌트도 위와 같이 매개변수로 구조 분해 할당하던 기존 코드를 변경하면 됩니다.
문제 확인
todo가 변하면 TodoContext.Provider에서 전달하는 모든 Props도 변하는 문제가 발생합니다.
→ 원인 : State 변수 todo와 dispatch관련 함수들이 하나의 객체로 묶여 동일한 Context에 Props로 전달되기 때문입니다.
재설계하기
Context를 역할에 따라 분리하기
export const TodoStateContext = React.createContext();
export const TodoDispatchContext = React.createContext();
( ... )
function App() {
( ... )
const memoizedDispatches = useMemo(() => {
return { onCreate, onUpdate, onDelete };
}, []);
return (
<div className="App">
<Header />
<TodoStateContext.Provider value={ todo }>
<TodoDispatchContext.Provider value={memoizedDispatches}>
<TodoEditor />
<TodoList />
</TodoDispatchContext.Provider>
</TodoStateContext.Provider>
</div>
);
}
export default App;
Context에서 데이터를 받는 자식 컴포넌트 수정하기
TodoEditor 컴포넌트
import { TodoDispatchContext } from "../App";
( ... )
const TodoEditor = () => {
const { onCreate } = useContext(TodoDispatchContext);
( ... )
};
≫ 나머지 컴포넌트도 알맞은 Context에서 데이터를 받도록 수정합니다.
1. App 컴포넌트에서 todo 공급할 TodoStateContext와 dispatch 함수를 공급할 TodoDispatchContext를 각각 만들어 배치하기 → dispatch 함수를 다시 생성하지 않도록 useMeomo를 이용하는건 미리 작성되어 있다.
import React, { useCallback, useMemo, useReducer, useRef } from "react";
( ... )
// 코드 작성
( ... )
function App() {
( ... )
const memoizedDispatches = useMemo(() => {
return { onCreate, onUpdate, onDelete };
}, []);
return (
<div className="App">
<Header />
// 코드 작성
</div>
);
}
export default App;
import React, { useCallback, useMemo, useReducer, useRef } from "react";
( ... )
export const TodoStateContext = React.createContext();
export const TodoDispatchContext = React.createContext();
( ... )
function App() {
( ... )
const memoizedDispatches = useMemo(() => {
return { onCreate, onUpdate, onDelete };
}, []);
return (
<div className="App">
<Header />
<TodoStateContext.Provider value={ todo }>
<TodoDispatchContext.Provider value={memoizedDispatches}>
<TodoEditor />
<TodoList />
</TodoDispatchContext.Provider>
</TodoStateContext.Provider>
</div>
);
}
export default App;
2. 1번에서 작성한 Context를 활용해 TodoList 컴포넌트가 todo를 받아 사용할 수 있도록 수정하기
import { TodoStateContext } from "../App";
( ... )
const TodoList = () => {
const todo = useContext(TodoStateContext);
( ... )
};
출처 : 이정환, 『한 입 크기로 잘라먹는 리액트』, 프로그래밍인사이트(2023)
Corner React.js 1
Editor: ssxbin
[React.js 1] 16. 리덕스 라이브러리 이해하기, 17. 리덕스를 사용하여 리액트 애플리케이션 상태 관리하기 (0) | 2024.01.19 |
---|---|
[React.js 1] project3. [감정 일기장] 만들기 (0) | 2024.01.12 |
[React.js 1] 7-8장. useReducer와 상태관리 & 최적화 (0) | 2023.12.29 |
[React.js 1] p2. 할 일 관리 앱 만들기(2) (1) | 2023.12.22 |
[React.js 1] p2. 할 일 관리 앱 만들기 (0) | 2023.12.01 |