리액트에 내장된 기능으로 props를 사용하지 않아도
특정 값이 필요한 컴포넌트끼리 쉽게 값을 공유할 수 있게 해준다.
Provider 하위에서 context를 공유하는 모든 컴포넌트는
Provider의 value props가 바뀔 때마다 다시 렌더링 된다.
주 목적: props-drilling을 피하는 것.
❗️참고) context는 아무것도 관리하지 않는다. 그저 값을 전달할 뿐이다.
import React, { createContext } from "react";
/* 변수에 저장해서 사용 */
export const MyContext = createContext(defaultValue);
/* defaultValue: Provider value값을 따로 지정하지 않았을 때 defaultValu의 값이 된다. */
Context 객체 안에는 Provider라는 컴포넌트가 들어있다.
공유하고자 하는 값을 value라는 Props로 설정하면
자식 컴포넌트에서 해당 값에 바로 접근을 할 수 있다.
<MyContext.Provider value={/* 어떤 값 */}>
{props.children}
<MyContext.Provider>
useContext라는 Hook을 사용하여
Context에 넣은 값에 접근할 수 있다.
/* useContext 가져오기 */
import React, { useContext } from "react";
import { UserContext } from "../store/store.js"
export const Child = () => {
const print = useContext(UserContext);
console.log(print) // userStore의 user 정보가 출력됨
store / user.js
/* createContext 가져오기 */
import React, { createContext } from "react";
export const UserContext = createContext(); /* 변수에 저장해서 사용 */
const UserStore = (props) => {
const [age, setAge] = useState(7);
const user = {
name: "TATA",
age,
changeAge: (update) => setAge(update),
};
return (
/* Provider의 value라는 Props를 설정하여 여러 컴포넌트에서 공유할 수 있다. */
<UserContext.Provider value={user}>{props.children}</UserContext.Provider>
);
}
export default = UserStore;
App.js
import UserStore from "./store.js"
...
function App() {
return (
<UserStore> /* 사용할 곳에 감싸주기 */
<Header />
<Child />
<Footer />
</UserStore> /* 사용할 곳에 감싸주기 */
)
}
Child.js
/* useContext 가져오기 */
import React, { useContext } from "react";
import { UserContext } from "../store/user.js"
export const Child = () => {
const print = useContext(UserContext);
console.log(print) // userStore의 user 정보가 출력됨
return (
...
)
}
useState의 대체 함수이다.
state가 많을 경우, state를 하나로 묶어주는 역할을 한다.
❗️참고) reducer는 순수함수이다.
const [state, dispatch] = useReducer(reducer, initialArg, init)
store / user.js
/* useReducer 가져오기 */
import React, { createContext, useReducer } from "react";
export const UserContext = createContext(); /* 변수에 저장해서 사용 */
const initialValue = {
name: "TATA",
age: 7,
}
const userReducer = (state, action) => {
switch (action.type) {
case "CHANGE_AGE":
return { ...state, age: action.number };
default:
break;
}
};
const UserStore = (props) => {
const [state, dispatch] = useReducer(userReducer, initialValue);
return (
/* Provider의 value로 dispatch를 줌 */
<UserContext.Provider value={{ state, dispatch }}>{props.children}</UserContext.Provider>
);
}
export default = UserStore;
App.js
import UserStore from "./store.js"
...
function App() {
return (
<UserStore> /* 사용할 곳에 감싸주기 */
<Header />
<Child />
<Footer />
</UserStore> /* 사용할 곳에 감싸주기 */
)
}
Child.js
/* useContext 가져오기 */
import React, { useContext } from "react";
import { UserContext } from "./store/user";
export const Child = () => {
const { dispatch, state } = useContext(UserContext);
const { age } = state;
const changeAgeFunc = () => {
return dispatch({ type: "CHANGE_AGE", number: "29" });
};
const resetAgeFunc = () => {
return dispatch({ type: "CHANGE_AGE", number: "7" });
};
return (
<>
<h2>Change TATA age</h2>
<h3>{age}살 입니다.</h3>
<button onClick={changeAgeFunc}>Real age</button>
<button onClick={resetAgeFunc}>Character age</button>
</>
);
};
✚ 참고
store / user.js
const initialValue = {
name: "TATA",
age: 7,
};
// 액션으로 분리
export const changeAgeAction = (number) => {
return {
type: "CHANGE_AGE",
payload: {
age: number,
},
};
};
const userReducer = (state, action) => {
switch (action.type) {
case "CHANGE_AGE":
return { ...state, age: action.payload.age };
default:
break;
}
};
Child.js
const changeAgeFunc = () => {
return dispatch(changeAgeAction(29));
};
const resetAgeFunc = () => {
return dispatch(changeAgeAction(7));
};