[React] useContext로 로그인 상태 관리하기
이번에 진행 중인 프로젝트에서 로그인 여부에 따라서 다르게 렌더링 해야 하는 컴포넌트가 늘어갔다.
로그인 여부를 전달하기 위해서 내가 선택한 방법은 최상단 컴포넌트에서 토큰을 확인해서 변수에 담아두는 방식이었다. 그리고 이 값이 필요한 자식 컴포넌트의 props 값으로 로그인 여부를 전달했다.
이러한 경우에는 A 컴포넌트는 로그인 여부 값이 필요하지 않지만 A 컴포넌트의 자식인 B 컴포넌트에는 그 값이 필요하기 때문에 A 컴포넌트도 로그인 여부 값을 가지고 있어야 한다. 컴포넌트 depth가 깊어 지거나 하면 관리가 복잡해지는 구조를 가지게 될 것이다.
그러다 React의 Context API를 알게되었다. context를 사용하면 데이터를 전역으로 관리하고 사용할 수 있다.
const App = () => {
const [isLoggedIn, setIsLoggedIn] = useState(false)
useEffect(() => {
const cookie = new Cookies()
setIsLoggedIn(cookie.get('auth_token') !== undefined)
}, [])
...
}
기존에는 위와 같이 App에서 쿠키를 가져와서 토큰이 있는지를 검사하고 그 boolean 값을 가지고 있는다.
(프론트단에서 로그인 여부를 쿠키 값으로 확인하는 게 올바른 방식인지 확인이 필요하다..)
그다음에는 아래 코드와 같이 해당 값이 필요한 자식 컴포넌트로 보내준다.
<Routes>
<Route path='/' element={<Home isLoggedIn={isLoggedIn} />}/>
...
</Routes>
Context API 적용하기
import React, { useState } from 'react'
import { useContext } from 'react'
import { Cookies } from 'react-cookie'
const token = new Cookies().get('auth_token')
export const LoginContext = React.createContext(null)
export const LoginProvider = ({ children }) => {
const [isLoggedIn, setIsLoggedIn] = useState(token !== undefined)
const value = {isLoggedIn, setIsLoggedIn}
return <LoginContext.Provider value={value}>{children}</LoginContext.Provider>
}
먼저 context를 사용하기 위해서 createContext를 사용해 LoginContext를 만든다. 기본값은 null로 지정했다. 로그인 여부를 판단하면서 새로운 value가 세팅이 되는데 이때 담기는 값들은 isLoggedIn와 setIsLoggedIn 변수이다.
export const useLoginContext = () => useContext(LoginContext)
다음은 로그인 상태를 업데이트하고 구독할 수 있는 커스텀 훅을 만들었다.
...
import { LoginProvider } from './shared/LoginContext.jsx'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<LoginProvider>
<App />
</LoginProvider>
</React.StrictMode>,
)
그리고 최상단 컴포넌트에서 LoginProvider로 하위 컴포넌트를 감싸준다.
const App = () => {
const {isLoggedIn, setIsLoggedIn} = useLoginContext()
const handleLogout = () => {
setIsLoggedIn(logout())
window.location.reload();
}
이제 위와 같이 useLoginContext를 불러오고 그 안에 들어있는 value를 담아준다. 바로 아래에 handleLogout 함수가 있는데 header부분을 컴포넌트로 나눠주지 않아서 이렇게 처리하게 만들어 놨다. 당연히 이 부분도 컴포넌트화를 진행해야 한다.
<Routes>
<Route path='/' element={<Home />}/>
...
</Routes>
이제는 Home 컴포넌트에게 로그인 여부 값을 전달하지 않아도 된다. Home에서 useLoginContext를 사용하고 그 안에서 값을 구독하면 된다.
Context API로 데이터를 전역에서 관리하는 방법을 배우고 프로젝트에 적용해 보았다. 아직 리팩터링이 필요한 부분이 많다는 걸 다시 알게 되었다. 그리고 로그인, 로그아웃, 회원가입 로직도 만들어둔 LoginContext를 이용하는 방식으로 다시 한번 리팩터링을 진행해야겠다.
Uploaded by N2T