일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 추상메서드
- 예외처리
- 오라클
- 자바
- exception
- 한국건설관리시스템
- oracle
- EnhancedFor
- 환경설정
- 집합_SET
- 참조형변수
- 객체 비교
- 컬렉션프레임워크
- 예외미루기
- Java
- 제네릭
- 대덕인재개발원
- 컬렉션 타입
- abstract
- 생성자오버로드
- GRANT VIEW
- 사용자예외클래스생성
- NestedFor
- 정수형타입
- cursor문
- 메소드오버로딩
- 인터페이스
- 다형성
- 자동차수리시스템
- 어윈 사용법
- Today
- Total
거니의 velog
(8) 프론트엔드 프로젝트 : 시작 및 회원 인증 구현 8 본문
(2) 로그인 상태를 보여 주고 유지하기
* 로그인 페이지에서 로그인에 성공하면 헤더 컴포넌트에서 로그인 중인 상태를 보여 주고, 새로고침을 해도 이 상태가 유지되도록 해 보자.
[1] 로그인 상태 보여주기
* 먼저 헤더 컴포넌트에 리덕스를 연결시켜 보자. containers 디렉터리에 common 디렉터리를 만들고, 그 안에 HeaderContainer 컴포넌트를 작성해 보자.
import React from 'react';
import { useSelector } from 'react-redux';
import Header from '../../components/common/Header';
const HeaderContainer = () => {
const { user } = useSelector(({ user }) => ({ user: user.user }));
return <Header user={user} />;
};
export default HeaderContainer;
* 헤더 컴포넌트에서 user 값이 주어질 경우 계정명과 로그아웃 버튼을 보여 주도록 수정하자.
[components/common/Header.js]
import React from 'react';
import styled from 'styled-components';
import Responsive from './Responsive';
import Button from './Button';
import { Link } from 'react-router-dom';
(...)
const UserInfo = styled.div`
font-weight: 800;
margin-right: 1rem;
`;
const Header = ({ user }) => {
return (
<>
<HeaderBlock>
<Wrapper>
<Link to="/" className="logo">
REACTERS
</Link>
{user ? (
<div className="right">
<UserInfo>{user.username}</UserInfo>
<Button>로그아웃</Button>
</div>
) : (
<div className="right">
<Button to="/login">로그인</Button>
</div>
)}
</Wrapper>
</HeaderBlock>
<Spacer />
</>
);
};
export default Header;
* 다음으로 PostListPage에서 Header 컴포넌트를 HeaderContainer로 대체하자.
[pages/PostListPage.js]
import React from 'react';
import HeaderContainer from '../containers/common/HeaderContainer';
const PostListPage = () => {
return (
<div>
<HeaderContainer />
<div>안녕하세요.</div>
</div>
);
};
export default PostListPage;
* 여기까지 작업한 뒤 로그인 페이지에서 로그인해 보자. 헤더 컴포넌트가 다음과 같이 나타날 것이다.
* 그런데 여기서 새로고침을 하면 상태가 초기화된다. 이를 유지시켜야만 한다.
[2] 로그인 상태 유지하기
* 로그인 상태를 유지하기 위해 브라우저에 내장되어 있는 localStorage를 사용할 것이다.
* LoginForm과 RegisterForm을 다음과 같이 수정해 주자.
[containers/auth/LoginForm.js]
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { withRouter } from 'react-router-dom';
import { changeField, initializeForm, login } from '../../modules/auth';
import AuthForm from '../../components/auth/AuthForm';
import { check } from '../../modules/user';
const LoginForm = ({ history }) => {
(...)
// 회원가입 성공/실패 처리
// user 값이 잘 설정되었는지 확인
useEffect(() => {
if (user) {
history.push('/');
try {
localStorage.setItem('user', JSON.stringify(user));
} catch (e) {
console.log('localStorage is not working');
}
}
}, [history, user]);
return (...);
};
export default withRouter(LoginForm);
* 회원가입 및 로그인을 하면 사용자 정보를 localStorage에 저장하도록 작업해 주었다. 페이지를 새로고침했을 때도 로그인 상태를 유지하려면, 리액트 앱이 브라우저에서 맨 처음 렌더링될 때 localStorage에서 값을 불러와 리덕스 스토어 안에 넣도록 구현해 주어야 한다.
* 이 작업은 App 컴포넌트에서 useEffect를 사용하여 처리하거나, App 컴포넌트를 클래스형 컴포넌트로 변환하여 componentDidMount 메서드를 만들고 그 안에서 처리해도 된다. 하지만 여기서는 프로젝트의 엔트리 파일인 index.js 에서 처리해 줄 것이다.
* 왜냐하면, componentDidMount와 useEffect는 컴포넌트가 한 번 렌더링된 이후에 실행되기 때문이다. 이 경우에는 사용자가 아주 짧은 깜박임 현상(로그인이 나타났다가 로그아웃이 나타나는 현상)을 경험할 수 있다. index.js에서 사용자 정보를 불러오도록 처리하고 컴포넌트를 렌더링하면 이러한 깜박임 현상이 발생하지 않는다.
* index.js를 다음과 같이 수정해 보자.
[src/index.js]
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import createSagaMiddleware from 'redux-saga';
import rootReducer, { rootSaga } from './modules';
import { tempSetUser, check } from './modules/user';
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(sagaMiddleware)),
);
function loadUser() {
try {
const user = localStorage.getItem('user');
if (!user) return; // 로그인 상태가 아니라면 아무것도 안함
store.dispatch(tempSetUser(user));
store.dispatch(check());
} catch (e) {
console.log('localStorage is not working');
}
}
sagaMiddleware.run(rootSaga);
loadUser();
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('root'),
);
* 위 코드를 작성할 때는 sagaMiddleware.run이 호출된 이후에 loadUser 함수를 호출하는 것이 중요하다. loadUser 함수를 먼저 호출하면 CHECK 액션을 디스패치했을 때 사가에서 이를 제대로 처리하지 않는다.
* 이제 로그인하고 나서 새로고침을 해 보자. 로그인 상태가 잘 유지되는가? 리덕스 개발자 도구를 통해 어떤 액션이 디스패치 되었는지, 리덕스 스토어는 어떤 상태를 가지고 있는지 확인해 보자.
* 현재 페이지가 새로고침될 때 localStorage에 사용자 정보가 들어 있다면 그 사용자 값을 리덕스 스토어에 넣는다. 그러고 나서 정말 사용자가 로그인 상태인지 CHECK 액션을 디스패치하여 검증하도록 했다.
* CHECK 액션이 디스패치되면 사가를 통해 /api/check API를 호출한다. 이 API는 성공할 수도 있고, 실패할 수도 있다. 만약 실패하면, 사용자 상태를 초기화해야 하고 localStorage에 들어 있는 값도 지워 주어야 한다.
[3] 로그인 검증 실패 시 정보 초기화
* 로그인 정보가 만료되었을 때를 대비하여 사용자 정보를 초기화하는 작업을 해 보겠다.
[modules/user.js]
import { createAction, handleActions } from 'redux-actions';
import { takeLatest } from 'redux-saga/effects';
import * as authAPI from '../lib/api/auth';
import createRequestSaga, {
createRequestActionTypes,
} from '../lib/createRequestSaga';
const TEMP_SET_USER = 'user/TEMP_SET_USER'; // 새로고침 이후 임시 로그인 처리
// 회원 정보 확인
const [CHECK, CHECK_SUCCESS, CHECK_FAILURE] =
createRequestActionTypes('user/CHECK');
export const tempSetUser = createAction(TEMP_SET_USER, (user) => user);
export const check = createAction(CHECK);
const checkSaga = createRequestSaga(CHECK, authAPI.check);
function checkFailureSaga() {
try {
localStorage.removeItem('user'); // localStorage 에서 user 제거
} catch (e) {
console.log('localStorage is not working');
}
}
export function* userSaga() {
yield takeLatest(CHECK, checkSaga);
yield takeLatest(CHECK_FAILURE, checkFailureSaga);
}
const initialState = {
user: null,
checkError: null,
};
export default handleActions(
(...)
initialState,
);
* checkFailureSaga라는 함수를 만들고, CHECK_FAILURE 액션이 발생할 때 해당 함수가 호출되도록 설정했다. 이 함수에서는 localStorage 안에 있는 user 값을 초기화해 준다. 스토어 안의 user 값은 리듀서에서 CHECK_FAILURE 액션이 발생했을 때 user 값을 null 로 설정하도록 이미 처리했으니 신경 쓰지 않아도 된다. 또한, checkFailureSaga 함수에서는 yield를 사용하지 않으므로 function*을 사용하여 제너레이터 함수 형태로 만들어 주지 않아도 괜찮다.
* 이제 로그인 정보가 유효하지 않을 때 로그인 정보 초기화 후 새로고침이 잘 되는지 확인해 보자. 쿠키를 초기화하고 페이지를 새로고침해 보자.
* 쿠키를 초기화할 때는 개발자 도구에서 Application 탭을 열고, Cookies > http://localhost:3000/ 을 선택한 다음 취소 아이콘을 누르면 된다.
* 쿠키를 초기화했다면 페이지를 새로고침해 보자. 로그인 정보가 잘 초기화 된다. 개발자 도구의 콘솔에서 console.log(localStorage.user); 를 입력해 보자. 초기화가 잘 되었다면 undefined가 나타나야 한다.
* undefined가 잘 나타나는가?
'React_프론트엔드 프로젝트' 카테고리의 다른 글
(10) 프론트엔드 프로젝트 : 글쓰기 기능 구현하기 1 (0) | 2024.02.23 |
---|---|
(9) 프론트엔드 프로젝트 : 시작 및 회원 인증 구현 9 (0) | 2024.02.23 |
(7) 프론트엔드 프로젝트 : 시작 및 회원 인증 구현 7 (0) | 2024.02.23 |
(6) 프론트엔드 프로젝트 : 시작 및 회원 인증 구현 6 (0) | 2024.02.22 |
(5) 프론트엔드 프로젝트 : 시작 및 회원 인증 구현 5 (0) | 2024.02.22 |