18. boilerplate - 회원가입 페이지
IT/프로젝트

18. boilerplate - 회원가입 페이지

반응형

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의 전체적인 구조와 로그인/토큰 유지/회원가입 과정 등등을 이해하는데 큰 도움이 됐다.
한번 쭉 만들어봤으니 이제는 좀 더 세부적으로 파고들어 그동안 이해를 제대로 못하고 넘어갔던 부분들을 다시 점검해보고 더 발전시켜봐야겠다. 이상~!

반응형