All'alba vincerò

At dawn, I will win!

React/한입 리액트

context: 컴포넌트 간의 데이터를 전달하는 기능

나디아 Nadia 2024. 4. 2. 22:03

 

 

 

 

📌 context

컴포넌트 간의 데이터를 전달할 수 있는 기능

 

  • 데이터 보관소(객체) 역할

 

 

 

  • props의 단점인 부모 👉 자식으로만 데이터를 전달하는 것을 해결한다.

✨ Props Drilling

: 컴포넌트 트리에서 데이터를 하위 컴포넌트로 전달하기 위해 중간 컴포넌트를 통해 프로퍼티를 내려주는 것

 

 

 

  • context는 여러 개 / 분리하여 설정할 수 있다.

 

 

 


 

 

📌 context 생성하기

📍 context 생성 메서드 불러오기

import { createContext } from 'react'

 

 

 

 

📍 context 선언하기

 

const 변수명 = createContext();

  • 컴포넌트 외부에 선언
    👉 굳이 App 컴포넌트가 리렌더링 될 때마다 재생성 될 필요가 없기 때문

 

 

 

 

📍 컴포넌트 감싸기

 

<변수명.Provider  value={공급할 데이터}>

    <컴포넌트 />

</ 변수명.Provider>

  • Provider 컴포넌트 내부의 컴포넌트들은 변수명 context의 데이터를 공급 받을 수 있다.
  • 공급할 데이터는 value로 전달
// context
const TodoContext = createContext();

  return (
    <div className='App'>       
      <Header/>
      
      <TodoContext.Provider value={{
        todos,
        onCreate,
        onUpdate,
        onDelete
      }}>
         <Editor onCreate={onCreate}/> 
         <List todos={todos} onUpdate={onUpdate} onDelete={onDelete}/>
      </TodoContext.Provider>
      
    </div>
  )

 

 

 


 

 

📌 context 사용하기

📍 context 불러오기

import { useContext } from "react"



 

 

 

📍 context 데이터 가져오기

 

🔺데이터가 있는 컴포넌트에서 context 내보내기

 

export const 변수명 = createContext();

export const TodoContext = createContext();

 

 

 

🔺 데이터를 사용할 컴포넌트에서 context 불러오기

 

import { 변수명 } from "../App";

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

 

 

 

 

 

📍 context 데이터 할당하기

 

useContext(데이터를 불러오고자 하는 context명);

  • useContext: 인수로 전달한 context로부터 공급된 데이터를 반환해주는 함수
  • 가져온 데이터를 구조 분해 할당을 통해 onCreate에 할당
const {onCreate} = useContext(TodoContext);

 

 

 


 

 

❓ TodoItem 컴포넌트를 memo 처리했는데도 리렌더링이 되는 이유 (=  최적화가 풀린 이유!)

새로운 Todo를 추가하거나 수정, 삭제할 경우, App 컴포넌트에 todos state가 변경되어 App 컴포넌트가 리렌더링 된다. 

👉  Provider 컴포넌트가 value props로 전달하는 객체 자체가 다시 생성된다.

 

 

❗TodoContext를 2개로 분리하여 해결한다. 

 

App.jsx

// context
// 변화할 값
export const TodoStateContext = createContext();
// 변화하지 않는 값
export const TodoDispatchContext = createContext();

  // TodoDispatchContext로 전달하는 데이터들은 변하지 않기 때문에 리렌더링이 불필요하다 => useMemo 사용
  const memoizedDispatch = useMemo(()=> {
    return {onCreate, onUpdate, onDelete};
  }, []); 
  // deps를 빈 배열로 뒀기 때문에 Mount 이후엔 재생성되지 않음!


  return (
    <div className='App'>       
      <Header/>

      <TodoStateContext.Provider value={todos}>
        <TodoDispatchContext.Provider value={memoizedDispatch}>
        <Editor/> 
        <List/>
        </TodoDispatchContext.Provider>
      </TodoStateContext.Provider>
      
    </div>
  )
}

 

 

Editor.jsx

import { useState, useRef, useContext } from "react"
import { TodoDispatchContext } from "../App";

// context로 데이터 꺼내기
const Editor = () => {
    const {onCreate} = useContext(TodoDispatchContext);
    // 구조분해할당

    ...
    
}

 

List.jsx

import { useState, useMemo, useContext } from "react";
import { TodoStateContext } from "../App";

const List = () => {
    const todos = useContext(TodoStateContext);
    // TodoStateContext.Provider의 value props로 객체인 {todos}를 전달했기 때문에 변수로 받아야 함

	...

}

 

TodoItem.jsx

import { TodoDispatchContext } from "../App";

const TodoItem = ({id, isDone, content, date}) => {
    // context 
    const {onUpdate, onDelete} = useContext(TodoDispatchContext);
    
    ...
    
}

 

 

최적화 성공

 

 

 


 

 

출처

한입 크기로 잘라먹는 리액트