Context 를 사용해보자
Context : 앱 전반에 걸쳐 같은 데이터를 공유하게 만들어 주는 HOOK
Context 의 기본 구성 요소
"1) createContext"
: createContext는, context 를 만들어주는 react의 빌트인 메서드이다.
[const myContext = createContext(defaultValue)]
* defaultValue는, "자동완성" 을 위해 사용한다고 해도 무방하다.
Provider 를 통해, "아무값도 넘기지 않으면", defaultValue 가 사용된다.
"2) context.Provider"
: Conetext.Provider 는, "context 를 구독하는 컴포넌트"들에게, "context 의 변화를 알린다".
[myContext.Provider value={값}]
Context 의 기본 사용
1) "context" 를 만든다.
2) "context를 공급할 곳" 에서, "만든 context를 import" 한다.
3) App.js 처럼, "전방위적으로 앱을 감싸는 컴포넌트"를 "context 로 감싼다."
4) 단 감쌀때는, "context 변화를 알리는, context.Provider" 로 "감싸야"한다. [공급한다.]
<context>
import { createContext } from "react";
const AuthContext = createContext({
isLoggedIn: false,
});
export default AuthContext;
<App.js>
import AuthContext from "../store/..."
...
<div className="App">
<AuthContext.Provider value={ {isLoggedIn: false} }>
<Login />
<NewExpenseon SaveChildData={saveExpenseDataHandler} />
<Expense fromNewExpense={expensData} yearValue={year} />
</AuthContext.Provider>
</div>
"기본 값 (defaultValue) 는 공급자가 없을때나, 유용한 것"이다. "Provider 가 전달하는 value 와는 전혀 관계 없다". 다만, "자동완성기능"을 위해 필요하다
Provder 는 value 를 하위 항목들에게 "공급"한다. "공급된 value" 는, "하위항목들도 접근하여 사용이 가능"하다.
지금은 <AuthContext.Provider value={ {isLoggedIn: false} }> 처럼 고정된 value 를 공급하지만,
App.js 에서 "State" 를 사용해, "동적으로 공급" 할 수도 있다.
useContext Hook 을 이용하여 사용(구독)하기
1) useContext 를 import 한다.
2) store 에 담겨있는 context 객체를 import 한다.
3) "useContext" 를 이용하여, "context를 구독"한다
4) context 를 사용한다.
< Login Component >
import useContext from "react"
import AuthContext from "../store/.."
function Login(){
const ctx = useContext(AuthContext)
retrun(
<div>
{ctx.isLoggedIn}
</div>
)
}
[헷갈리는것, 반드시 알아야 할 것!]
** 컨텍스트를 Provide 하는 "Provider는", "context 에 있는 isLoggedIn 을 전달 하는 것이 아니다."
스스로 적은 "value" 객체를 전달하는 것이다.
"이 말인 즉, 굳이 store 폴더에서, defaultValue 를 적지 않아도, "
Provider의 value 를 통해, "아무 값(혹은 함수)이나 추가하여 전달 할 수 있다는 것"이다.
[context 에서 정의하지 않아서, 자동완성은 안되겠지만]
** 이는 보통, "context의 상태(데이터)를 변화하는 함수들을 추가하여 전달" 할것이다.
<App.js>
import AuthContext from "../store/..."
const [isLogin, setIsLogin] = useState(false)
...
function changeState (...){
setIsLogin(...)
}
<div className="App">
<AuthContext.Provider value={ {isLoggedIn: isLogin, onClick={changeState}} }>
<Login />
<NewExpenseon SaveChildData={saveExpenseDataHandler} />
<Expense fromNewExpense={expensData} yearValue={year} />
</AuthContext.Provider>
</div>
** 사용하는 곳에서 "useContext" 를 사용하여, "함수를 받아 사용"한다면, "App.js" 에서 정의된 함수이므로,
App.js 의 "isLogin State" 가 변하고, 이는 "공급할 isLoggedIn 의 value 가 바뀔것"이고
"이는 구독하여 사용하는 모든 곳에 있는 value 가 바뀔것"이다.
store 의 Context 안에서, 모든 공급이 이루어 지도록, 조정하도록 하자
공급하는 곳에, 중구난방 코드를 적지 않기 위하여 리팩토링 하는 것이다.
1. 기본 사용 메커니즘
1. store에 context를 만들어, App.js 에 .Proivder 를 이용해, 하위 컴포넌트들을 감싸, value 를 넘긴다.
2. value 는, App.js 의 .Proivder 안에서 정의되며, App.js의 함수와 State를 모든 앱에 걸쳐 공급한다.
3. App.js 에서 정의된 함수와 State 를 넘겨받은 하위 컴포넌트들은,
useState 를 사용하여, vlaue 에 접근해, value 를 사용한다.
value 에 넣어 공급할, State와, 함수들을 App.js 에서 정의하기에, 복잡해진다.
2. 리팩토링한 메커니즘
1. AuthContext 를 Provide 하기위한 함수를 재정의 [AuthContextProvider]
2. 재정의한 AuthContextProvider 를 export 하고, 반환값으로, AuthContext.Proivder 태그 안에,
props.children 을 사용해 Provider 태그로 모든 하위 컴포넌트를 감싼다. = 공급한다.
3. value = { {name: ..., login: ...} } 처럼 각각의 객체를 정의하지 말고,
context 라는 변수를 만들어, value 안에 넣어준다. 실질적으로 공급되는 값들은 context 인것이다.
4. context 안에는, "State" 와 "함수(State를 조작할)" 가 들어간다. (반드시 그럴 필요는 없다)
5. createContext 로 만든 AuthContext 안에는 defaultValue 가 들어간다.
defaultValue 는 단지, "자동완성"을 위한 값일 뿐이다.
어차피 Proivder를 사용한다면, defaultValue의 데이터는 필요없다.
<store/AuthContext.js> ================================================================================
import { createContext, useState } from "react";
const AuthContext = createContext({
isLoggedIn: false,
loginHandler: ()=>{},
logoutHandler:()=>{}
});
export function AuthContextProvider(props) {
const [isLoggedIn, setIsLoggedIn] = useState(false);
function loginHandler() {
setIsLoggedIn(true);
}
function logoutHandler() {
setIsLoggedIn(false);
}
const context = {
isLoggedIn: isLoggedIn,
loginHandler: loginHandler,
logoutHandler: logoutHandler,
};
return (
<AuthContext.Provider value={context}>
{props.children}
</AuthContext.Provider>
);
}
export default AuthContext;
< App.js > ================================================================================
: 기존에" AuthContext를 이용해, .Proivder 메서드로, 공급했다".
하지만 그 일은, 이제, "AuthContextProvider" 가 대신할것이다.
또한, App.js 에서 Provider 을 사용할 필요가 없어졌다.
[전부 모이는 "index.js" 에 가서, "AuthContextProvider" 로 감싸준다.]
< index.js > ================================================================================
import { AuthContextProvider } from "./store/auth-context";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<AuthContextProvider>
<Layout>
<App />
</Layout>
</AuthContextProvider>
);
< 사용할 곳 > ================================================================================
: 이제 사용할 곳에서 똑같이, "createContext로 만든, AuthContext 를 import" 하고,
"useContext" 를 이용하여, "Provider 내부에 있는 값을 사용"하면된다.
import { useContext, useState } from "react";
import AuthContext from "../../store/auth-context";
function UseContextPractice() {
const ctx = useContext(AuthContext);
function login() {
ctx.loginHandler(); // true
}
function logout() {
ctx.logoutHandler();
}
console.log(ctx.isLoggedIn); // false
return (
<div>
<button onClick={login}> 컨텍스트 로그인 </button>
<button onClick={logout}> 컨텍스트 로그아웃</button>
</div>
);
}
export default UseContextPractice;
Context 를 사용할 때 주의사항
반드시 "매우매우 긴 props chain" 과 "전반적인 앱을 컨트롤하는 State"를 이용할때 (Auth, 전체 Banner 등..) 만 사용한다.
"자주 바뀌는 State" 에 관해서는 "Context" 를 사용하지 않는다! - 리액트 개발자의 공식문서
그래서 "Redux" 를 사용할것이다.
'React > React-Basic' 카테고리의 다른 글
7. 리액트의 최적화 With React.memo(), useCallback(), useMemo() (0) | 2022.12.14 |
---|---|
6. className, style 다루기 (0) | 2022.12.12 |
4. useReducer 바로 알기 - 기본편 (0) | 2022.12.08 |
3. useEffect 바로알기 with. 클린업 프로세스, 디바운싱 (0) | 2022.12.08 |
2. React Portal 사용해보기 (0) | 2022.12.07 |
댓글