# React 블로그 - 로그인 구현

[**https://electricburglar.tistory.com/155**](https://electricburglar.tistory.com/155)

**React로 블로그 만들기 #8**

&#x20;**- 로그인 구현(5) 새로고침 후 로그인 유지 -**

**1. 로그인 유지**

\- 로그인을 한다고 해도 자동으로 로그인 상태가 유지되지 않는다.\
\- 브라우저를 닫거나 새로고침할 시 스토어 값이 초기화되므로 페이지에 다시 들어왔을 때 로그인을 유지하는 로직이 필요하다.

\- TodoApp에서는 쿠키를 이용하여 로그인을 유지하였지만, 블로그 앱에서는 HTML5에서 제공하는Web Storage API를 사용한다.

\- 또한 로그아웃 시 소셜로그인으로 발급받은 토큰을 제거하도록 로직을 추가해야함.

**2. localStorage vs sessionStorage**<br>

\- Key와 Value 값으로 저장.

\- 문자열이 아닌 객체도 저장이 가능하며 5MB까지 저장 가능함.

\- 쿠키와 다르게 만료기간을 지정할 수 없으며, 서버로 전송되지 않음.

\- 자동로그인을 원하면 localStorage를 사용하고 브라우저를 닫으면 로그인이 풀리는 것을 원하면 sessionStorage를 사용

1\) localStorage

\- 사용자가 지우지 않는 이상 영구적으로 계속 브라우저에 남아있음.

\- 따라서 지속적으로 필요한 정보를 저장한다. (자동로그인 등)

2\) sessionStorage

\- 윈도우나 브라우저를 닫는 경우 사라지며 뿐만 아니라 브라우저 내에서 탭을 생성하는 경우에도 별도의 영역으로 할당됨.

\- 잠시동안 필요한 정보를 저장한다. (일회성 로그인 등)

**3. 구현하기**

1\) src/Components/Login.js

\- 소셜로그인 성공 시 받은 정보를 세션스토리지에 저장함.

```
import React, { Component } from 'react';
import { GoogleLogin } from 'react-google-login';
import KakaoLogin from 'react-kakao-login';
import styled from 'styled-components';
import { withRouter } from "react-router-dom";
class Login extends Component {
constructor(props) {
super(props);
this.state = {
id: '',
name: '',
provider: '',
 }
 }
// Google Login
responseGoogle = (res) => {
this.setState({
id: res.googleId,
name: res.profileObj.name,
provider: 'google'
 });
this.doSignUp();
 }
// Kakao Login
responseKakao = (res) => {
this.setState({
id: res.profile.id,
name: res.profile.properties.nickname,
provider: 'kakao'
 });
this.doSignUp();
 }
// Login Fail
responseFail = (err) => {
console.error(err);
 }
doSignUp = () => {
const { id, name, provider } = this.state;
window.sessionStorage.setItem('id', id);
window.sessionStorage.setItem('name', name);
window.sessionStorage.setItem('provider', provider);
this.props.onLogin();
this.props.history.push('/');
 }
render() {
return (
<Container>
<GoogleLogin
clientId={process.env.REACT_APP_Google}
buttonText="Google"
onSuccess={this.responseGoogle}
onFailure={this.responseFail}
/>
<KakaoButton
jsKey={process.env.REACT_APP_Kakao}
buttonText="Kakao"
onSuccess={this.responseKakao}
onFailure={this.responseFail}
getProfile="true"
/>
</Container>
 );
 }
}
const Container = styled.div`
 display: flex;
 flex-flow: column wrap;
`
const KakaoButton = styled(KakaoLogin)`
 padding: 0;
 width: 190px;
 height: 44px;
 line-height: 44px;
 color: #783c00;
 background-color: #FFEB00;
 border: 1px solid transparent;
 border-radius: 3px;
 font-size: 16px;
 font-weight: bold;
 text-align: center;
`
export default withRouter(Login);

```

2\) src/App.js

\- componentDidMount함수에서 세션스토리지에 id가 있는 경우 onLogin함수를 실행하고 없을 경우에는 onLogout함수를 실행하여 로그인을 유지함.

\- 또한 로그아웃 시, 소셜로그인으로 부터 전달받은 토큰을 제거하고 세션스토리지에 저장된 정보를 모두 삭제한다.

```
import React, { Component } from 'react';
import styled from 'styled-components';
import Header from './Layout/Header';
import Navigation from './Layout/Navigation';
import Router from './Routes/Router';
import Store from './Store/store';
class App extends Component {
constructor(props) {
super(props)
this.state = {
logged: false,
onLogin: this.onLogin,
onLogout: this.onLogout
 }
 }
// Login Func
onLogin = () => {
this.setState({
logged: true
 });
 }
// Logout Func
onLogout = () => {
this.setState({
logged: false
 });
const provider = window.sessionStorage.getItem('provider');
//Google AccessToken Remove
if(provider === 'google') {
const auth2 = window.gapi.auth2.getAuthInstance();
auth2.signOut().then(function() {
console.log('Goolge Logout.');
 });
 }
// Kakao AccessToken Remove
else if(provider === 'kakao'){
window.Kakao.Auth.logout(function() {
console.log("Kakao logout");
 });
 }
//SessionStorage Clear
window.sessionStorage.clear();
 }
componentDidMount() {
const id = window.sessionStorage.getItem('id');
if(id) {
this.onLogin();
 }
else {
this.onLogout();
 }
 }
render() {
const { logged, onLogout } = this.state;
return (
<Store.Provider value={this.state}>
<Layout>
<Header logged={logged} onLogout={onLogout}/>
<Navigation />
<Content>
<Router />
</Content>
</Layout>
</Store.Provider>
 );
 }
}
const Layout = styled.div`
 margin: 0 auto;
 display: flex;
 width: 100%;
 flex-flow: row wrap;
`
const Content = styled.div`
 margin: 0 auto;
`
export default App;

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://blog.javabom.com/minhee/session/storage/localstorage-sessionstorage/react.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
