
: props를 오로지 하위 컴포넌트로 전달하는 용도로만 쓰이는 컴포넌트들을 거치면서 React Component 트리의 한 부분에서 다른 부분으로 데이터를 전달하는 과정
: Provider와 Provider가 공급하는 데이터를 받을수 있는 컴포넌트들의 영역

단, Provider컴포넌트의 자손이 아닌 컴포넌트는 Provider 컴포넌트가 공급하는 데이터를 받을 수 없음. 같은 문맥(context)이 아님.
// Context 생성
const MyContext = React.createContext(defaultValue);
// Context Provider를 통한 데이터 공급
<MyContext.Provider value={전역으로 전달하고자 하는 값}>
{/* 해당 Context안에 위치할 자식 컴포넌트들 */}
</MyContext.Provider>
// Context API를 이용해서 data state를 전역으로 공급할 Context 생성
// Context도 export해줘야 다른 컴포넌트들이 Context에 접근하여 Provider가 공급하는 데이터를 받아올 수 있음.
export const DiaryStateContext = React.createContext();
return (
<DiaryStateContext.Provider>
<div className="App">
<OptimizeTest />
{/* <Lifecycle /> */}
<DiaryEditor onCreate={onCreate} />
<div>전체 일기 : {data.length}</div>
<div>기분 좋은 일기 개수 : {goodCount}</div>
<div>기분 나쁜 일기 개수 : {badCount}</div>
<div>기분 좋은 일기 비율 : {goodRatio}</div>
<DiaryList diaryList={data} onRemove={onRemove} onEdit={onEdit} />
</div>
</DiaryStateContext.Provider>
);

return (
<DiaryStateContext.Provider value={data}>
<div className="App">
<OptimizeTest />
{/* <Lifecycle /> */}
<DiaryEditor onCreate={onCreate} />
<div>전체 일기 : {data.length}</div>
<div>기분 좋은 일기 개수 : {goodCount}</div>
<div>기분 나쁜 일기 개수 : {badCount}</div>
<div>기분 좋은 일기 비율 : {goodRatio}</div>
<DiaryList diaryList={data} onRemove={onRemove} onEdit={onEdit} />
</div>
</DiaryStateContext.Provider>
);

import { useContext } from "react";
import { DiaryStateContext } from "./App"; // App에서 export한 Context를 비구조화할당을 통해 import 받아와서 사용해야함
import DiaryItem from "./DiaryItem";
// diaryList 데이터는 더 이상 App()에서 prop으로 받아올 필요가 없음
const DiaryList = ({ onRemove, onEdit }) => {
// Context에서 데이터를 받기 위해서 useContext Hook 사용
const diaryList = useContext(DiaryStateContext);
diaryList.map((lst) => {});
return (
<div className="DiaryList">
<h2>일기 리스트 ({diaryList.length})</h2>
<div>
{diaryList.map((lst, idx) => (
<DiaryItem
key={lst.id}
{...lst}
onRemove={onRemove}
onEdit={onEdit}
/>
))}
</div>
</div>
);
};

// App.js
return (
<DiaryStateContext.Provider value={data}>
<div className="App">
<OptimizeTest />
{/* <Lifecycle /> */}
<DiaryEditor onCreate={onCreate} />
<div>전체 일기 : {data.length}</div>
<div>기분 좋은 일기 개수 : {goodCount}</div>
<div>기분 나쁜 일기 개수 : {badCount}</div>
<div>기분 좋은 일기 비율 : {goodRatio}</div>
// DiaryList로 전달해주던 diaryList prop 삭제
<DiaryList onRemove={onRemove} onEdit={onEdit} />
</div>
</DiaryStateContext.Provider>
);
<DiaryStateContext.Provider value={data} />에 onCreate(), onReve(), onEdit()을 props로 모두 전달하면 안됨!
-> Provider도 컴포넌트이기 때문
prop이 바뀌어버리면 컴포넌트가 재생성됨 -> Provider 하위에 있는 컴포넌트들도 모두 재생성됨
Provider에 data상태값 변경 함수들을 prop으로 내려주게 되면, data state가 바뀔때마다 리랜더링이 일어남
새로운 context를 생성하여 data를 전달하는 context와 data 상태 변경 함수를 전달하는 context를 분리해서 사용하면 됨
새로운 context 생성
// App.js
// state 변화 함수들을 공급할 context 생성
export const DiaryDispatchContext = React.createContext();
// onCreate(), onEdit(), onRemove()함수를 하나로 묶어서 전달
// memoizedDispatchFunc가 재생성되지 않도록 useMemo의 depth를 빈배열로 전달
const memoizedDispatchFunc = useMemo(() => {
return { onCreate, onRemove, onEdit };
}, []);
// 새롭게 만든 DiaryDispatchContext.Provider를 DiaryStateContext.Provider 바로 하단 자식요소로 추가
return (
<DiaryStateContext.Provider value={data}>
// dispatch 함수들을 prop으로 전달
<DiaryDispatchContext.Provider value={memoizedDispatchFunc}>
<div className="App">
<OptimizeTest />
{/* <Lifecycle /> */}
<DiaryEditor /> {/* prop으로 전달하던 dispatch 함수 제거 */}
<div>전체 일기 : {data.length}</div>
<div>기분 좋은 일기 개수 : {goodCount}</div>
<div>기분 나쁜 일기 개수 : {badCount}</div>
<div>기분 좋은 일기 비율 : {goodRatio}</div>
<DiaryList /> {/* prop으로 전달하던 dispatch 함수 제거 */}
</div>
</DiaryDispatchContext.Provider>
</DiaryStateContext.Provider>
);
useMemo를 활용하여 dispatch 함수들을 묶는 이유
const dispatchesFunc = { onCreate, onRemove, onEdit }과 같이 객체로 만들면 App컴퍼넌트가 재생성될 때 dispatchesFunc 객체도 재생성되기 때문

// DiaryEditor.js
import React, { useContext, useEffect, useRef, useState } from "react";
import { DiaryDispatchContext } from "./App";
const DiaryEditor = () => {
// onCreate props 받기 (DiaryStateContext에서는 받아올 수 없음)
// DiaryDispatchContext 안에서 객체 형태로 함수가 전달되기 때문에 비구조화 할당으로 받아와야함
const { onCreate } = useContext(DiaryDispatchContext);
// DiaryList.js
const DiaryList = () => {
/* Props로 전달하던 onEdit, onRemove 제거 */
const diaryList = useContext(DiaryStateContext);
diaryList.map((lst) => {});
return (
<div className="DiaryList">
<h2>일기 리스트 ({diaryList.length})</h2>
<div>
{diaryList.map((lst, idx) => (
<DiaryItem key={lst.id} {...lst} />
))}
</div>
</div>
);
};
// diaryItem.js
import React, { useContext, useEffect, useRef, useState } from "react";
import { DiaryDispatchContext } from "./App";
const DiaryItem = ({
/* Props로 받던 onEdit, onRemove 삭제 */
author,
content,
emotion,
created_date,
id,
}) => {
const { onRemove, onEdit } = useContext(DiaryDispatchContext);
export default /// export 차이
Context export 시, export default로 사용 X
- export default는 파일 하나당 한 번만 쓸 수 있음
- export만 사용하면 여러개 사용 가능
import React, { useEffect, useMemo, useRef, useCallback, useReducer, } from "react";
- React는 그냥 import하는데, 나머지 기능들은 {}안에서 비구조화 할당을 통해 import 받고 있음
- 비구조화 할당을 통해 받는 기능들은 import 시 이름을 바꿀 수 없지만, React는 이름을 변경하여 import 할 수 있음
from "react"의 react파일에서 export default로 내보내졌으면 이름을 바꿔서 (React) 받아올 수 있고, 그냥 export로 내보내진 컴포넌트는 그 이름을 비구조화 할당을 통해서만 받아올 수 있음- App.js에서는 기본적으로 App() 컴포넌트를 내보내고 있고, 부가적으로 DiaryStateContext같은 컴포넌트(?)를 내보내고 있는 것.