6-6. 새로고침 할 시 로그인 유지하기
로그인을 한다고해서, 기본적으론 앱 내에서 자동으로 로그인 상태가 유지되지 않습니다. 브라우저를 새로고침하면 스토어 값이 초기화되기 때문인데요, 그렇기 때문에 페이지에 들어왔을 때 유저정보를 다시 넣어주는 작업이 필요합니다.
이 작업은 다음 과정을 거쳐서 구현됩니다.
- App 이 불러와졌을 때 로컬스토리지에 있던 유저 정보 사용
- 서버에 현재 로그인 상태 재검증
- 서버가 응답한 로그인 정보로 업데이트
- 만약에 토큰이 만료되었을 시에는, 재로그인 요청
src/App.js
import React, { Component } from 'react';
import { Route } from 'react-router-dom';
import { Home, Auth } from 'pages';
import HeaderContainer from 'containers/Base/HeaderContainer';
import storage from 'lib/storage';
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux';
import * as userActions from 'redux/modules/user';
class App extends Component {
initializeUserInfo = async () => {
const loggedInfo = storage.get('loggedInfo'); // 로그인 정보를 로컬스토리지에서 가져옵니다.
if(!loggedInfo) return; // 로그인 정보가 없다면 여기서 멈춥니다.
const { UserActions } = this.props;
UserActions.setLoggedInfo(loggedInfo);
try {
await UserActions.checkStatus();
} catch (e) {
storage.remove('loggedInfo');
window.location.href = '/auth/login?expired';
}
}
componentDidMount() {
this.initializeUserInfo();
}
render() {
return (
<div>
<HeaderContainer/>
<Route exact path="/" component={Home}/>
<Route path="/auth" component={Auth}/>
</div>
);
}
}
export default connect(
null,
(dispatch) => ({
UserActions: bindActionCreators(userActions, dispatch)
})
)(App);
코드를 저장하고, 페이지를 새로고침 한 다음에, 리덕스 개발자 도구를 통해 상태를 조회해보세요.
로그아웃 임시구현
우리는 나중에 다음과 같은 유저 메뉴를 구현하게 됩니다.
이 유저메뉴를 구현하기 전에, 미리 임시적으로 로그아웃 기능을 구현해보도록 하겠습니다.
src/containers/Base/HeaderContainer.js
import React, { Component } from 'react';
import Header, { LoginButton } from 'components/Base/Header';
import { connect } from 'react-redux';
import * as userActions from 'redux/modules/user';
import { bindActionCreators } from 'redux';
import storage from 'lib/storage';
class HeaderContainer extends Component {
handleLogout = async () => {
const { UserActions } = this.props;
try {
await UserActions.logout();
} catch (e) {
console.log(e);
}
storage.remove('loggedInfo');
window.location.href = '/'; // 홈페이지로 새로고침
}
render() {
const { visible, user } = this.props;
if(!visible) return null;
return (
<Header>
{ user.get('logged')
? (<div>
{user.getIn(['loggedInfo', 'username'])} <div onClick={this.handleLogout}>(로그아웃)</div>
</div> )
: <LoginButton/>
}
</Header>
);
}
}
export default connect(
(state) => ({
visible: state.base.getIn(['header', 'visible']),
user: state.user
}),
(dispatch) => ({
UserActions: bindActionCreators(userActions, dispatch)
})
)(HeaderContainer);
로그아웃을 할 때에는, 로그아웃 요청을 하고, 로컬스토리지도 비워주어야 합니다.
로그인 만료시 에러메시지 띄우기
우리가 App 컴포넌트를 수정 할 때, 로컬스토리지에는 로그인 정보가 있는데 서버측에서는 로그인 상태가 아니라고 할 때는 /auth/login?expired 경로로 이동하게 했었습니다.
이번엔, 로그인 페이지에서 expired 파라미터가 존재하면 에러메시지를 띄워보겠습니다.
쿼리를 파싱하기 위해서 query-string
을 설치하세요.
$ yarn add query-string
그리고, Login 컴포넌트의 componentDidMount 를 다음과 같이 수정하세요.
src/containers/Auth/Login.js
(...)
import queryString from 'query-string';
class Login extends Component {
componentDidMount() {
const { location } = this.props;
const query = queryString.parse(location.search);
if(query.expired !== undefined) {
this.setError('세션에 만료되었습니다. 다시 로그인하세요.')
}
}
(...)
코드를 다 작성하셨다면 http://localhost:3000/auth/login?expired 링크로 이동해보세요.
메시지가 잘 떴나요?