import React from 'react'
// createContext는 기본 컨텍스트를 만든다.
// 여기서의 컨텍스트는 빈 state의 컴포넌트일 뿐이다.
// 이후 이 state가 어떤 모습을 갖추어야 하는지는 개발자의 의도에 달려있다.
// 대부분의 경우에는 객체를 입력한다.
// AuthContext 자체는 컴포넌트가 아니지만, 컴포넌트를 감싸는 객체이다.
const AuthContext = React.createContext({
isLoggedIn: false
})
// 다른 컴포넌트,파일에서도 사용할 수 있게 export한다.
// 작성한 Context를 사용하기 위해서는 두가지 작업을 수행해야 한다.
// 1. 공급 : JSX 코드로 감싸는 것을 뜻한다.
// 기본적으로 React에게 Context가 어디있는지 알려준다.
// AuthContext로 감싸인 컴포넌트는, AuthContext를 소비할 수 있는 자격을 얻는다.
// 2. 리스닝: AuthContext에 접근하기 위해서는 두가지 리스닝 방법이 존재한다.
// AuthContext.Consumer 또는 React Hook을 사용하는데, 일반적으로는 React Hook을 사용한다.
//
export default AuthContext
function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
useEffect(() => {
const storedUserLoggedInInformation = localStorage.getItem('isLoggedIn');
if (storedUserLoggedInInformation === '1') {
setIsLoggedIn(true);
}
}, []);
const loginHandler = (email, password) => {
// We should of course check email and password
// But it's just a dummy/ demo anyways
localStorage.setItem('isLoggedIn', '1');
setIsLoggedIn(true);
};
const logoutHandler = () => {
localStorage.removeItem('isLoggedIn');
setIsLoggedIn(false);
};
return (
// AuthContext 자체가 컴포넌트가 되지는 않는다. 하지만 JSX에 호출하려면 컴포넌트가 필요하다.
// 컴포넌트의 역할은 Provider로 호출한다.
// AuthContext.Provider로 감싸인 Component는 이제 AuthContext에 작성된 객체에 접근할 수 있다.
// 그리고 value 프롭스에 전달하려는 객체를 전달한다.
// value에 전달하는 isLoggedIn 객체가 변경될 때마다, 감싸인 Component에게 변경된 isLoggedIn이 전달된다.
<AuthContext.Provider value={isLoggedIn}>
<MainHeader isAuthenticated={isLoggedIn} onLogout={logoutHandler} />
<main>
{!isLoggedIn && <Login onLogin={loginHandler} />}
{isLoggedIn && <Home onLogout={logoutHandler} />}
</main>
</AuthContext.Provider>
);
}
export default App;
App component에서 존재하는 state,함수를 props drilling없이 AuthContext.Propvider로 감싸인 컴포넌트에게 전달할수도 있다.
function App() {
...
const [isLoggedIn, setIsLoggedIn] = useState(false);
const logoutHandler = () => {
localStorage.removeItem('isLoggedIn');
setIsLoggedIn(false);
};
...
return(
...
<AuthContext.Provider value={{
isLoggedIn, // isLoggedIn:isLoggedIn
onLogout: logoutHandler
}}>
)
...
// Navigation.js에서는 사용자가 인증되었는지 여부를 확인해야한다.
// 이를 위해서 작성한 AuthContext를 사용할 수 있다.
// useContext는 Context를 사용하게 해주며, 리스닝할 수 있게 한다.
// 사용법은 간단하다. Component 함수에서 useContext를 호출한 뒤
// Context에게 사용하려는 Context를 가리키는 Pointer를 전달하기만 하면 된다.
import React, {useContext} from 'react';
import AuthContext from '../store/auth-context';
import classes from './Navigation.module.css';
const Navigation = (props) => {
// useContext를 호출하고 상수에 저장한다.
const ctx = useContext(AuthContext)
//이제 AuthContext의 객체에 접근할 수 있다.
return (
<nav className={classes.nav}>
<ul>
{ctx.isLoggedIn && (
<li>
<a href="/">Users</a>
</li>
)}
{ctx.isLoggedIn && (
<li>
<a href="/">Admin</a>
</li>
)}
{ctx.isLoggedIn && (
<li>
<button onClick={props.onLogout}>Logout</button>
</li>
)}
</ul>
</nav>
);
};
export default Navigation;
useContext를 사용하여 props는 더이상 Navigation.js에서 사용되지 않는다.
{ctx.isLoggedIn && (
<li>
{/* props가 아닌 useContext를 사용하여 ctx.onLogout을 실행.*/}
<button onClick={ctx.onLogout}>Logout</button>
</li>
)}
const AuthContext = React.createContext({
// dummy 함수와 dummy value를 저장하는 이유는
// IDE 자동 완성을 더 좋게 만들기 위해서다.
isLoggedIn: false,
onLogout: () => {},
onLogIn: (email,password) => {}
})
// 데이터를 관리하는 방법에 따라 다르지만,
// 더 많은 로직을 가져와서 사용해야 하는 경우가 있을 수 있다.
// 이렇게 하는 이유는, 이제 AuthContextProvider 컴포넌트를 통해
// useState를 import 하여
// App.js가 아닌, AuthContextProvider에서 state와 함수를 직접 관리할 수 있기 때문이다.
export const AuthContextProvider = ({children}) => {
const [isLoggedIn,setIsLoggedIn] = useState();
useEffect(() => {
const storedUserLoggedInInformation = localStorage.getItem('isLoggedIn');
if (storedUserLoggedInInformation === '1') {
setIsLoggedIn(true);
}
}, []);
const logoutHandler = () => {
localStorage.removeItem('isLoggedIn');
setIsLoggedIn(false);
}
const loginHandler = () => {
localStorage.setItem('isLoggedIn', '1');
setIsLoggedIn(true);
}
return <AuthContext.Provider value={{isLoggedIn,onLogin:loginHandler,onLogout:logoutHandler}}>{children}</AuthContext.Provider>
}
export default AuthContext
function App() {
const ctx = useContext(AuthContext)
return (
//App component에서 존재하는 state,함수를
//props drilling없이 AuthContext.Propvider로 감싸인 컴포넌트에게 전달할수도 있다.
<>
<MainHeader onLogout={ctx.logoutHandler} />
<main>
{!ctx.isLoggedIn && <Login />}
{ctx.isLoggedIn && <Home />}
</main>
</>
);
}
export default App;