boilerplate 유튜브 강의 시리즈
Blog ReactJS NodeJS #25 REGISTER PAGE
드디어 마지막 강의이다.. ㅋㅋ
10월부터 듣기 시작했는데 11월에 계약직 일을 하고 우아한테크코스 준비도 좀 하느라 늦어졌다. 는 핑계 ~
아무튼 마지막까지 왔다는 게 뿌듯하다.ㅎㅎ
마지막 강의에서는 회원가입 페이지를 만든다.
전에 만들어 두었던 register.js에 회원가입 컴포넌트 클래스를 만들것이다.
1. 회원가입 컴포넌트 클래스 생성
components > RegisterLogin > register.js
import React, { Component } from 'react';
class Register extends Component {
render() {
return (
<div>
hello Register page
</div>
);
}
}
export default Register;
2. 회원가입 페이지 라우터 연결
App.js
import React from 'react';
import {Route, Switch} from 'react-router-dom';
import About from './about';
import Login from './RegisterLogin';
import Register from './RegisterLogin/register';
function App() {
return (
<div>
<Switch>
<Route path="/about" component={About}/>
<Route path="/login" component={Login}/>
<Route path="/register" component={Register}/>
</Switch>
</div>
);
}
export default App;
3. 회원가입 버튼 추가
components > RegisterLogin > index.js
// Link를 import한다.
import {Link} from 'react-router-dom';
// 기존 로그인 버튼
// col 12 -> col 6 으로 변경
<div className="col 6">
<button
className="btn waves-effect red lighten-2"
type="submit"
name="action"
onClick={this.submitForm}
>
Login
</button>
</div>
// 로그인 버튼 아래에 회원가입 버튼 추가
<div className="col 6">
<Link to="/register">
<button
className="btn waves-effect red lighten-2"
type="submit"
name="action"
>
Sign up
</button>
</Link>
</div>
회원가입 버튼 테스트
4. 회원가입 type, action, reducer
actions > types.js
- REGISTER_USER 추가
export const LOGIN_USER = 'login_user';
export const REGISTER_USER = 'register_user';
actions > user_actions.js
- 회원가입 요청 결과를 return 하는 registerUser 함수 추가
import axios from 'axios';
import {
LOGIN_USER,
REGISTER_USER
} from './types';
export function loginUser(dataToSubmit) {
const request = axios.post('/api/users/login', dataToSubmit)
.then(response => response.data);
return {
type: LOGIN_USER,
payload: request,
}
}
export function registerUser(dataToSubmit) {
const request = axios.post('/api/users/register', dataToSubmit)
.then(response => response.data);
return {
type: REGISTER_USER,
payload: request,
}
}
reducers > user_reducers.js
- 회원가입 요청 후 액션을 받아 상태를 변경한다.
import {
LOGIN_USER,
REGISTER_USER
} from '../actions/types';
export default function userReducer(state={}, action) {
switch (action.type) {
case LOGIN_USER:
return {...state, loginSuccess: action.payload};
case REGISTER_USER:
return {...state, success: action.payload};
default:
return state;
}
}
5. 회원가입 컴포넌트 클래스 최종
- 로그인 컴포넌트와 전체적인 구조는 비슷하다.
import React, { Component } from 'react';
import {connect} from 'react-redux';
import {registerUser} from '../../actions/user_actions';
class Register extends Component {
state = {
lastname: '',
name: '',
email: '',
password: '',
passwordConfirmation: '',
errors: []
};
displayErrors = errors => errors.map((error, i) => <p key={i}>{error}</p>);
handleChange = event => {
this.setState({ [event.target.name]: event.target.value });
}
isFormValid = () => {
const errors = [];
const form = document.getElementsByTagName('form')[0];
if (this.isFormEmpty(this.state)) {
this.setState({errors: errors.concat('Fill in all fields')});
} else if(!form.checkValidity()) {
this.setState({errors: errors.concat('Email is invalid')});
} else if (!this.isPasswordValid(this.state)) {
this.setState({errors: errors.concat('Password is invalid')});
} else {
return true;
}
}
isPasswordValid = ({password, passwordConfirmation}) => {
if (password.length < 6 || passwordConfirmation.length < 6) {
return false;
} else if (password !== passwordConfirmation) {
return false;
} else {
return true;
}
}
isFormEmpty = ({lastname, name, email, password, passwordConfirmation}) => {
return (
!name.length ||
!lastname.length ||
!email.length ||
!password.length ||
!passwordConfirmation.length
);
}
submitForm = event => {
event.preventDefault();
let dataToSubmit = {
email: this.state.email,
name: this.state.name,
lastname: this.state.lastname,
password: this.state.password,
passwordConfirmation: this.state.passwordConfirmation,
};
if (this.isFormValid()) {
this.setState({errors: []});
this.props.dispatch(registerUser(dataToSubmit))
.then(response => {
if (response.payload.success) {
this.props.history.push('/login');
} else {
this.setState({
errors: this.state.errors.concat('your attempt to send data to DB was faild')
})
}
})
.catch(err => {
this.setState({
errors: this.state.errors.concat(err)
})
})
} else {
console.error('Form is not valid');
}
}
render() {
return (
<div className="container">
<h2> Sign Up </h2>
<div className="row">
<form className="col s12">
<div className="row">
<div className="input-field col s12">
<input
name="lastname"
value={this.state.lastname}
onChange={e => this.handleChange(e)}
id="lastname"
type="text"
className="validate"
/>
<label htmlFor="lastname">lastname</label>
<span
className="helper-text"
data-error="Type a right type email"
data-success="right"
/>
</div>
</div>
<div className="row">
<div className="input-field col s12">
<input
name="name"
value={this.state.name}
onChange={e => this.handleChange(e)}
id="name"
type="text"
className="validate"
/>
<label htmlFor="name">name</label>
<span
className="helper-text"
data-error="wrong"
data-success="right"
/>
</div>
</div>
<div className="row">
<div className="input-field col s12">
<input
name="email"
value={this.state.email}
onChange={e => this.handleChange(e)}
id="email"
type="email"
className="validate"
/>
<label htmlFor="email">email</label>
<span
className="helper-text"
data-error="wrong"
data-success="right"
/>
</div>
</div>
<div className="row">
<div className="input-field col s12">
<input
name="password"
value={this.state.password}
onChange={e => this.handleChange(e)}
id="password"
type="password"
className="validate"
/>
<label htmlFor="password">Password</label>
</div>
</div>
<div className="row">
<div className="input-field col s12">
<input
name="passwordConfirmation"
value={this.state.passwordConfirmation}
onChange={e => this.handleChange(e)}
id="passwordConfirmation"
type="password"
className="validate"
/>
<label htmlFor="passwordConfirmation">Password Confirmation</label>
</div>
</div>
{this.state.errors.length > 0 && (
<div>
{this.displayErrors(this.state.errors)}
</div>
)}
<div className="row">
<div className="col 12">
<button
className="btn waves-effect red lighten-2"
type="submit"
name="action"
onClick={this.submitForm}
>
Create an account
</button>
</div>
</div>
</form>
</div>
</div>
);
}
}
export default connect()(Register);
6. 회원가입 테스트
몽고 DB
7. 로그인 테스트
드디어 강의를 모두 마쳤다..
강사님이 빠트린 부분도 있고 빠른 진행을 위해 코드의 정리가 안된 부분도 있어서 여기서 다듬고 살을 붙이는 작업을 더 해야 한다.
auth, logout 을 포함한 전체 코드는 강사님 깃허브에 올라와있다.
https://github.com/jaewonhimnae/boilerplate-mern-stack
아무튼 강의를 통해 react, redux의 전체적인 구조와 로그인/토큰 유지/회원가입 과정 등등을 이해하는데 큰 도움이 됐다.
한번 쭉 만들어봤으니 이제는 좀 더 세부적으로 파고들어 그동안 이해를 제대로 못하고 넘어갔던 부분들을 다시 점검해보고 더 발전시켜봐야겠다. 이상~!
'IT > 프로젝트' 카테고리의 다른 글
17. boilerplate - 로그인 페이지 (2) (0) | 2021.01.03 |
---|---|
16. boilerplate - 로그인 페이지 (1) (0) | 2021.01.02 |
15. boilerplate - redux 세팅 (0) | 2021.01.02 |
14. boilerplate - proxy 설정 및 concurrently 적용 (0) | 2021.01.01 |
13. boilerplate - react router dom (0) | 2021.01.01 |