Props Drilling이 발생하고 있는 컴포넌트에게
Context를 사용하여 문제점을 개선해보자.
먼저 저번 시간에도 활용했던 투두리스트 앱을 활용해보자.
1. Props Drilling 발생 지점 찾기
현재 투두리스트에서 발생하고 있는 Props Drilling을
살펴보자.
App컴포넌트에서 만든 onUpdate와 onDelete함수는최종적으로
TodoItem 컴포넌트에 전달되어야하는데그러기 위해
List컴포넌트에게 먼저 props로 전달되고List컴포넌트에서 다시 props로 TodoItem까지 전달된다.이 과정에서 Props Drilling이 발생하고있다.




2. Context 생성
먼저 컨텍스트를 사용하기 위해서는 새로운 컨텍스트를 만들어야한다.
createContext를 App컴포넌트에서 불러오자.
새로운 컨텍스트 객체 생성해주자.
이 때 컨텍스트 객체를 생성하는 곳은 컴포넌트 외부이다.
컨텍스트의 역할은 단순히 데이터를 하위에 있는 컴포넌트에게
전달해주기만 하면 되는데 계속해서 리렌더링 할 필요가 없기 때문이다.
const TodoContext = createContext();컨텍스트를 사용해보기 전에 이렇게 만들어진
컨텍스트 객체에 어떤 값들이 있는지 콘솔에 출력해서 살펴보자.
아래 이미지에서 확인할 수 있듯 컨텍스트는 여러 값을
가지고 있는데 그 중에서도 우리가 중요하게 볼 것은
Provider라는 프로퍼티이다.프로바이더는 공급자라는 뜻으로 이 컨텍스트가 공급할
데이터를 설정하거나 이 컨텍스트의 데이터를 공급받을
컴포넌트를 설정하는 역할을 한다.

이러한 프로바이더는 컴포넌트로서 사용할 수 있다.
App컴포넌트에서 props를 전달받고 있는두 컴포넌트를 감싸는 형태로 사용할 수 있다.
<div className="App">
<Header />
<TodoContext.Provider>
<Editor onCreate={onCreate} />
<List todos={todos} onUpdate={onUpdate} onDelete={onDelete} />
</TodoContext.Provider>
</div>여기까지 바꾼 뒤 컴포넌트의 계층을 살펴보자.
기존에 우리 앱의 컴포넌트 계층은 다음과 같은 구조였다.

여기서
TodoContext객체를 만들고,TodoContext.Provider컴포넌트에게 Provider 설정을 했다.그럼 다음 이미지처럼 프로바이더 컴포넌트로 묶은
컴포넌트들은
App이 아닌 프로바이더의 하위 컴포넌트가 된다.
그리고 프로바이더 컴포넌트의
value속성으로props로 전달했던 요소들을 객체 형태로 넣어주면
컨텍스트로 하위에 있는 모든 컴포넌트에게 전달할 수 있게 된다.
<TodoContext.Provider
value={{
todos,
onCreate,
onUpdate,
onDelete,
}}
>
<Editor />
<List />
</TodoContext.Provider>;
프로바이더로 감싼 상위 컴포넌트 뿐만 아니라
상위에 있는 컴포넌트의 아래에 존재하는 모든 컴포넌트에
직접적으로 데이터를 공급할 수 있다!

따라서
TodoItem도 프로바이더에게 직접 데이터를전달받을 수 있게 된다.

실제로 프로바이더 컴포넌트는
value에 객체의 형태로전달받은 props의 모든 값이 잘 들어가 있다.

3. Context로 데이터 공급받기
그럼 이제 데이터를 공급받을 컴포넌트를 살펴보자.
1. Editor 컴포넌트
먼저
onCreate 함수를 전달받던 Editor컴포넌트부터 시작하자.우선 props로 전달받던 값들은 이제 삭제해주자.
// <Editor onCreate={onCreate} />
<Editor />그리고
Editor컴포넌트에서 받던 props도 삭제하고useContext 훅을 추가해주자.
그리고 컨텍스트를 호출하여 인수로는 우리가 데이터를
전달받을 컨텍스트의 이름을 직접 적으면 된다.
const data = useContext(TodoContext);이를
data라는 변수에 저장해서 콘솔에 출력하면TodoContext에서 받을 수 있는 모든 데이터가 나타나는데Editor컴포넌트에서 사용할 데이터만 구조분해할당 문법으로 받아주자.
const { onCreate } = useContext(TodoContext);추가 기능이 잘 된다!

2. List 컴포넌트
List와 TodoItem 컴포넌트에도 컨텍스트로값을 전달해주자.
먼저 List 컴포넌트에 전달하던 props를 제거하자.
// <List todos={todos} onUpdate={onUpdate} onDelete={onDelete} />
<List />똑같이
useContext 훅을 불러오고 props값을 비우자.
List컴포넌트에서 필요한 값은
todos이다.구조분해할당으로
todos값만 context로 들고오자.const { todos } = useContext(TodoContext);3. TodoItem 컴포넌트
TodoItem도 같은 방법으로 수정해보자.// <TodoItem key={todo.id} {...todo} onUpdate={onUpdate} onDelete={onDelete} />;
<TodoItem key={todo.id} {...todo} />;
const { onUpdate, onDelete } = useContext(TodoContext);여기까지 모두 완료되면 이전처럼 앱의 기능이 모두
정상적으로 돌아가며 props drliing 현상까지 개선할 수 있다.
하지만 문제점이 하나 발생하는데 이전에 했던
최적화 작업이 풀려 하나의 TodoItem을 수정해도
나머지 모든 TodoItem이 같이 리렌더링 된다는 것이다.

이 현상은 다음 글에서 같이 개선해보도록 하자.
Share article