📌 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);
...
}
출처
한입 크기로 잘라먹는 리액트