본문 바로가기
웹 프로그래밍/Next.js

[유데미 | winterlood 이정환] 프로젝트로 배우는 React.js & Next.js 마스터리 클래스 강의 내용 정리 (섹션 10: Context)

by 청량리 물냉면 2024. 1. 13.
반응형

섹션 10: Context

Props Drilling

TodoList 앱의 컴포넌트 트리

붉은 표시가 되어 있는 onUpdate, onDelete 함수TodoList 컴포넌트에 구현되어 있지만 실제로 컴포넌트에 직접적으로 필요한 함수는 아니다. App 컴포넌트에서 생성된 함수를 TodoItem으로 내려주어야 하기 때문에 구현되어 있을 뿐이다.

만약 이러한 현상이 tree depth가 깊은 앱에서 발생했다면, 의미 없이 아래 depth로 props를 내려주기만 하는 컴포넌트들이 많아지며 자연히 코드의 길이도 길어지고 코드 내용도 복잡해질 것이다.

 

Props Drilling 해결 방안: Context

Context: 자식 컴포넌트들에게 데이터를 직송으로 보내줄 수 있는 객체

 

Context 사용법

Context 생성

 

TodoContext.jsx

import { createContext } from "react";

export const TodoContext = createContext();

 

 

App 컴포넌트에서 <Context.Provider>로 props를 내려줄 컴포넌트를 감싼다.

App.jsx

  return (
    <div className="App">
      <Header />
      <TodoContext.Provider value={{ todos, onCreate, onUpdate, onDelete }}>
        <TodoEditor onCreate={onCreate} />
        <TodoList todos={todos} onUpdate={onUpdate} onDelete={onDelete} />
      </TodoContext.Provider>
    </div>
  );

 

최종적으로 아래 이미지와 같이 Context에서 각 컴포넌트에 필요한 값만 내려보내 준다.

 

 

 

예시) TodoEditor.jsx

...
export default function TodoEditor({ onCreate }) {
  const [content, setContent] = useState("");
  const inputRef = useRef();

  ...
  return (
    ...
  );
}

👇

...
import { TodoContext } from "../TodoContext";

export default function TodoEditor() {
  const { onCreate } = useContext(TodoContext);

  const [content, setContent] = useState("");
  const inputRef = useRef();

  ...

  return (
    ...
  );
}

 

그러나 체크박스를 체크/해제를 반복하며 확인해 보면 이전에 적용해 두었던 최적화가 풀리는 문제가 발생한다.

 

문제 원인

Context도 컴포넌트이기 때문에, 상위 컴포넌트인 App 컴포넌트가 변경되면 Context 컴포넌트도 리렌더링 된다. Context가 리렌더링되면 하위 컴포넌트도 모두 리렌더링되므로 위와 같은 문제가 발생한다.

이를 해결하기 위해 Context를 분리할 필요가 있다. 

 

 

최적화를 위한 Context 분리 기법 살펴보기

바뀔 필요가 있는 값만 바뀌도록 Context를 분리해 준다.

 

TodoContext.jsx

import { createContext } from "react";

export const TodoStateContext = createContext();
export const TodoDispatchContext = createContext();

 

App.jsx

  //TodoDispatchContext 내부 value 객체가 재생성되지 않도록 막는 코드(재생성되지 않는 객체를 전달해주기 위해)
  const memoizedDispatches = useMemo(() => {
    return { onCreate, onUpdate, onDelete };
  }, []);

  return (
    <div className="App">
      <Header />
      <TodoStateContext.Provider value={todos}>
        <TodoDispatchContext.Provider value={memoizedDispatches}>
          <TodoEditor />
          <TodoList />
        </TodoDispatchContext.Provider>
      </TodoStateContext.Provider>
    </div>
  );

 

TodoItem.jsx

function TodoItem({ id, isDone, createdDate, content }) {
  const { onUpdate, onDelete } = useContext(TodoDispatchContext);

 

 

 

 

출처

https://kmooc.udemy.com/course/react-next-master/learn/lecture/39610746

반응형