리액트에서 전역적으로 사용할 데이터가 있을 때 유용하며 리덕스, 리액트 라우터, styled-components 등의 라이브러리는 Context API를 기반으로 구현되어 있다.
상세코드에서 확인해볼 수 있다.
주로 전역적으로 필요한 상태를 관리할 때는 최상위 컴포넌트인 App의 state에 넣어서 관리한다. 그러나 컴포넌트가 많아지는 경우 유지 보수성이 낮아질 수 있다. 이에 따라 Context API를 사용하면 Context를 만들어 한 번에 원하는 값을 받아 사용할 수 있다.
createContext()
함수를 사용하여 생성한다.
// contexts/color.js
import { createContext } from "react";
const ColorContext = createContext({ color: "black" });
export default ColorContext;
Context
안에 있는 Consumer
라는 컴포넌트를 통해 색상을 조회한다.
Render Props란 컴포넌트의 children이 있어야 할 자리에 일반 JSX 혹은 문자열이 아닌 함수를 전달하는 것이다.
// components/ColorBox.js
import React from "react";
import ColorContext from "../contexts/color";
const ColorBox = () => {
return (
<ColorContext.Consumer>
{(value) => (
<div
style={{
width: "64px",
height: "64px",
background: value.color,
}}
/>
)}
</ColorContext.Consumer>
);
};
export default ColorBox;
Provider
를 통해 Context
의 vaule를 변경할 수 있다. 전에 createContext({ color: 'black' }); 처럼 기본값을 넣었는데 이는 Provider
를 사용하지 않은 경우에만 사용한다. Provider
사용시 value를 반드시 명시해야 한다.
// App.js
import ColorBox from "./components/ColorBox";
import ColorContext from "./contexts/color";
import React from "react";
const App = () => {
return (
<ColorContext.Provider value={{ color: "red" }}>
<div>
<ColorBox />
</div>
</ColorContext.Provider>
);
};
export default App;
useContenxt
훅을 사용하면 함수 컴포넌트에서 Context
를 쉽게 사용할 수 있다. 일반적으로 전 컴포넌트에서 공유되어야 하는 값이 있을 때만 사용하며, 각 컴포넌트로 별로만 관리하는 값일 경우 useState
를 쓰는 것이 더 적절하다.
const UserContext = createContext();
<UserContext.Provider value={ 여러 컴포넌트에서 사용하고 싶은 값 }>
<UserList />
</UserContext.Provider>
import { UserContext } from '../App'
const { value 에 넘겨줬던 키 } = useContext(UserContext)
// App.js
import React, { createContext } from "react";
import Detail from "./pages/Detail";
export let Context1 = createContext();
const App = () => {
let sendData = [1, 2, 3, 4, 5];
return (
<>
<Context1.Provider value={{ sendData }}>
<Detail />
</Context1.Provider>
</>
);
};
// Detail.js
import React, { useContext } from 'react';
import { Context1 } from '../App';
const Detail = () => {
let getData = useContext(Context1);
console.log(getData); // [1,2,3,4,5]
return ()
};
// app.js
import { UserProvider } from "./contexts/UserContext";
import UserList from "./components/UserList";
function App() {
return (
<UserProvider>
<UserList />
</UserProvider>
);
}
export default App;
// contexts/UserContext.jsx
import React, { createContext, useReducer } from "react";
import { userReducer } from "../reducers/userReducer";
import { userData } from "../constants/userData";
export const UserContext = createContext(null);
// 위에서 선언한 두가지 Context 들의 Provider 로 감싸주는 컴포넌트
export function UserProvider({ children }) {
const [state, dispatch] = useReducer(userReducer, userData);
return (
<UserContext.Provider value={{ state, dispatch }}>
{children}
</UserContext.Provider>
);
}
// userList.jsx
import React, { useContext } from "react";
import { UserContext } from "../contexts/UserContext";
import UserDetail from "./UserDetail";
function UserList() {
const { state: users } = useContext(UserContext);
return (
<div>
<h1>리스트 짜잔</h1>
{users.map((user) => (
<UserDetail key={user.id} user={user} />
))}
</div>
);
}
export default UserList;
// userDetail.jsx
import React, { useContext } from "react";
import { UserContext } from "../contexts/UserContext";
function UserDetail({ user }) {
const { dispatch } = useContext(UserContext);
return (
<div key={user.id}>
<p>{user.name}</p>
<button
onClick={() =>
dispatch({ type: "UPDATE", data: { id: user.id, name: "변경됨" } })
}
>
이름 바꾸기
</button>
<button
onClick={() => dispatch({ type: "REMOVE", data: { id: user.id } })}
>
삭제하기
</button>
</div>
);
}
export default UserDetail;
소중한 정보 감사드립니다!