import React from 'react'; // 라이브러리의 React객체 불러오기
const MyContext = React.createContext(defaultValue); // createContext 메서드를 호출해 새로운 Context 만들기
provider 컴포넌트는 Props로 공급할 데이터를 받아, 컴포넌트 트리에서 자신보다 하위에 있는 모든 컴포넌트에 데이터를 공급한다.
import React from "react";
const MyContext = React.createContext(defaultValue);
function App() {
const data = "data";
return (
<div>
<Header />
<MyContext.provider value={data}>
<Body />
</MyContext.provider>
</div>
);
}
export default App;
import React, { useContext } from "react"; // useContext를 react 라이브러리에서 불러오기
const MyContext = React.createContext(defaultValue);
function App() {
const data = "data";
return (
<div>
<Header />
<MyContext.provider value={data}>
<Body />
</MyContext.provider>
</div>
);
}
function Main() {
const data = useContext(MyContext); // useContext를 호출하고 Context를 전달, useContext는 해당 Context가 공급하는 값을 반환
(...)
}
export default App;
Context를 이용한 데이터 공급 구조
어떻게 Context를 적용할지 생각해 보기
TodoContext를 만들어 데이터 공급하기
// App.js
import React, { useReducer, useRef, useCallback } from "react";
(...)
const TodoContext = React.createContext(); // TodoContext 만들기
function App() {
(...)
}
export default App;
// App.js
import React, { useReducer, useRef, useCallback } from "react";
(...)
const TodoContext = React.createContext();
function App() {
(...)
return (
<div className="App">
<Header />
<TodoContext.Provider value={{ todo, onCreate, onUpdate, onDelete }}> // Props(value)를 객체로 설정
<TodoEditor /> // 기존의 Props 제거
<TodoList /> // 기존의 Props 제거
</TodoContext.Provider>
</div>
);
}
export default App;
// TodoList.js
const TodoList = ({ todo, onUpdate, onDelete }) => {
(...)
}
TodoList.defaultProps = {
todo: [],
};
export default TodoList;
TodoList 컴포넌트에서 Context 데이터 사용하기
// App.js
(...)
export const TodoContext = React.createContext();
(...)
// TodoList.js
import { useContext, useState, useMemo } from "react"; // useContext 불러오기
import { TodoContext } from "../App"; // TodoContext 불러오기
(...)
const TodoList = ({ todo, onUpdate, onDelete }) => {
const storeData = useContext(TodoContext); // useContext를 호출하고 TodoContext를 인수로 전달해 storeData에 저장하기
console.log(storeData); // storeData를 콘솔에 출력
(...)
};
(...)
// TodoList.js
const TodoList = () => {
const { todo, onUpdate, onDelete } = useContext(TodoContext);
(...)
};
export default TodoList;
TodoItem 컴포넌트에서 Context 데이터 사용하기
// TodoList.js
const TodoList = () => {
const { todo } = useContext(TodoContext); // todo 외의 나머지 삭제
(...)
return (
<div className="TodoList">
(...)
<div className="list_wrapper">
{
getSearchResult().map((it)=> (
<TodoItem key={it.id} {...it} /> // 기존에 Props으로 전달하던 코드도 삭제
))
}
</div>
</div>
);
};
export default TodoList;
// TodoItem.js
import React, { useContext } from "react"; // useContext 불러오기
import { TodoContext } from "../App"; // TodoContext 불러오기
(...)
const TodoItem = ({ id, content, isDone, createDate }) => { // onDelete, onUpdate 삭제
const { onDelete, onUpdate } = useContext(TodoContext); // useContext을 호출해 TodoContext의 값을 불러와 구조 분해 할당
(...)
};
export default React.memo(TodoItem);
TodoEditor 컴포넌트에서 데이터 공급하기
// TodoEditor.js
import { useContext, useState, useRef } from "react"; // useContext 불러오기
import { TodoContext } from "../App"; // TodoContext 불러오기
(...)
const TodoEditor = () => {
const { onCreate } = useContext(TodoContext); // useContext을 호출해 TodoContext의 값을 불러와 구조 분해 할당
(...)
};
(...)
리팩토링이 잘 되었는지 확인하기 1
// TodoItem.js
(...)
const TodoItem = ({ id, content, isDone, createDate }) => {
console.log(`${id} TodoItem 업데이트`); // 컴포넌트를 렌더링할 때마다 콘솔 메세지 출력
(...)
};
export default React.memo(TodoItem);
문제의 원인 파악하기
구조 재설계하기
재설계된 구조로 변경하기
// App.js
export const TodoStateContext = React.createContext(); // TodoStateContext 만둘기
export const TodoDispatchContext = React.createContext(); // TodoDispatchContext 만들기
function App() {
(...)
return (
<div className="App">
<Header />
<TodoStateContext.Provider value={{ todo }}> // Props 전달
<TodoDispatchContext.Provider value={{ onCreate, onUpdate, onDelete }}> // Props 전달
<TodoEditor />
<TodoList />
</TodoDispatchContext.Provider>
</TodoStateContext.Provider>
</div>
);
}
export default App;
// App.js
import React, { useMemo, useReducer, useRef, useCallback } from "react"; // useMemo 불러오기
(...)
function App() {
(...)
const memoizedDispatches = useMemo(()=> { // useMemo로 onCreate, onUpdate, onDelete를 묶기
return { onCreate, onUpdate, onDelete };
}, []);
return (
<div className="App">
<Header />
<TodoStateContext.Provider value={{ todo }}>
<TodoDispatchContext.Provider value={memoizedDispatches}> // memoizedDispatches 전달
<TodoEditor />
<TodoList />
</TodoDispatchContext.Provider>
</TodoStateContext.Provider>
</div>
);
}
export default App;
// TodoEditor.js
(...)
import { TodoDispatchContext } from "../App"; // TodoDispatchContext 불러오기
(...)
const TodoEditor = () => {
const { onCreate } = useContext(TodoDispatchContext); // useContext를 호출하여 TodoDispatchContext에서 함수 onCreate 불러오기
(...)
};
export default TodoEditor;
// TodoList.js
(...)
import { TodoStateContext } from "../App"; // TodoStateContext 불러오기
(...)
const TodoList = () => {
const todo = useContext(TodoStateContext); // TodoStateContext 데이터 가져오기, todo 배열 그 자체를 전달
(...)
};
export default TodoList;
// TodoItem.js
(...)
import { TodoDispatchContext } from "../App"; // TodoDispatchContext 가져오기
(...)
const TodoItem = ({ id, content, isDone, createDate }) => {
console.log(`${id} TodoItem 업데이트`);
const { onDelete, onUpdate } = useContext(TodoDispatchContext); // TodoDispatchContext의 데이터 중 onDelete, onUpdate를 불러옴
(...)
};
export default React.memo(TodoItem);
리팩토링이 잘 되었는지 확인하기 2
1. ( Context )란 같은 문맥 아래에 있는 컴포넌트 그룹에 데이터를 공급하는 기능이다.
2. [1번 답]을 사용하는 이유는 ( Props Drilling 문제 )를 해결하기 위해서다.
3. [2번 답]이란 Props가 ( 중간에 있는 여러 컴포넌트 )를 통해 전달되어야 하는 경우이다.
4. ( ContextAPI )란 Context를 만들고 다루는 리액트 기능이다.
5. ( provider 컴포넌트 )는 Props로 공급할 데이터를 받아, 컴포넌트 트리에서 자신보다 하위에 있는 모든 컴포넌트에 데이터를 공급한다.
6. Context를 이용한 데이터 공급 구조는 ( createContext )를 이용해 Context를 만들기 -> 값을 공급할 컴포넌트를 ( Context.Provider)로 감싸기 -> 함수 ( useContext )를 호출해 Context가 공급하는 값을 불러와 사용하기이다.
1. Context를 생성하고, provider 컴포넌트를 이용하여 Props로 공급할 데이터를 받아 컴포넌트 트리에서 자신보다 하위에 있는 Body 컴포넌트에 데이터를 공급하시오.
import React from "react";
// 여기에 코드 작성
function App() {
const data = "data";
return (
<div>
<Header />
// 여기에 코드 작성
</div>
);
}
export default App;
2. MyContext가 공급하는 데이터를 사용하시오.
import React, { useContext } from "react";
const MyContext = React.createContext(defaultValue);
function App() {
const data = "data";
return (
<div>
<Header />
<MyContext.provider value={data}>
<Body />
</MyContext.provider>
</div>
);
}
function Main() {
// 여기서 코드 작성
(...)
}
export default App;
1.
import React from "react";
const MyContext = React.createContext(defaultValue);
function App() {
const data = "data";
return (
<div>
<Header />
<MyContext.provider value={data}>
<Body />
</MyContext.provider>
</div>
);
}
export default App;
2.
import React, { useContext } from "react";
const MyContext = React.createContext(defaultValue);
function App() {
const data = "data";
return (
<div>
<Header />
<MyContext.provider value={data}>
<Body />
</MyContext.provider>
</div>
);
}
function Main() {
const data = useContext(MyContext);
(...)
}
export default App;
출처 : 이정환, 『한 입 크기로 잘라먹는 리액트』, 프로그래밍인사이트(2023), p386-407.
Corner React.js 3
Editor: lyonglyong
[리액트 스타터3] 16장 리덕스 라이브러리 이해하기 17장 리덕스를 사용하여 리액트 애플리케이션 상태 관리하기 (1) | 2024.01.19 |
---|---|
[리액터 스타터3] project 3 [감정 일기장] 만들기 (0) | 2024.01.12 |
[리액터 스타터3] 7장 useReducer와 상태 관리 / 8장 최적화 (0) | 2023.12.29 |
[리액터 스타터3] project 2. [할 일 관리] 앱 만들기 2 (1) | 2023.12.22 |
[리액터 스타터3] project 2. [할 일 관리] 앱 만들기 1 (1) | 2023.12.01 |