나홀로 프로젝트 진행 중, 정리하지 않으면 도저히 안될것 같아서 회원가입부터 정리를 시작

스택

  • Frontend: React (redux, axios)
  • Backend: NodeJs, express
  • DB: MongoDB

구현 순서

  1. 모델 설계
  2. 백엔드 로직 구현
  3. 프론트 컴포넌트 구현
  4. Redux action, reducer와 axios로 데이터 통신

모델 설계

const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const saltRounds = 10;

const userSchema = mongoose.Schema({
    name: {
        type: String,
        trim: true,
        unique: 1
    },
    password: {
        type: String,
        minlength: 5
    },
    token: { type: String,
 },
    tokenTime: {
 type: Number,
 },
})

userSchema.pre('save', function (next) {
    var user = this;

    if (user.isModified('password')) {
        bcrypt.genSalt(saltRounds, function (err, salt) {
            if (err) return next(err);
            bcrypt.hash(user.password, salt, function (err, hash) {
                if (err) return next(err);
                user.password = hash
                next()
            })
        })
    } else {
        next()
    }
});

const User = mongoose.model('User', userSchema);
module.exports = { User }

원래 모델에 다른 속성도 많은데 회원가입 기능에 관한 것만 정리하기 위해서 간단하게 정리했다.

먼저 회원스케마를 먼저 설계하고, 모델로 하기 전에 회원에 관해 처리해야할 method들을 구현한다.

.pre(‘save’)는 회원을 저장하기 전에 해야할 일들로, bcrypt를 이용해서 password를 Hash로 암호화하기 위한 로직이다.

스케마에 로직을 설계 후, model로 만들고 export한다. 이제 User를 불러와서 db관련 처리를 할 수 있다.

백엔드 로직 구현

const express = require('express');
const router = express.Router();
const {User} = require('../models/User');

router.post("/register", (req, res) => {
    const user = new User(req.body);
    user.save((err, doc) => {
        if (err) return res.json({ success: false, err });
        return res.status(200).json({
            success: true
        });
    });
});

module.exports = router;

(express.Router()를 사용해서 index와 router를 분리해놓은 상태)

먼저 import한 User모델을 이용해 객체를 생성한다. 이때 client단에서 보낸 정보를 담아야 한다.

그리고 save()를 이용해 저장하고, 성공할 때와 실패할 때의 처리를 모두 해준다.

프론트 컴포넌트 구현

import React, {useState} from 'react'
import {useDispatch} from 'react-redux'
import {registerUser} from '../../../_actions/user_actions'

export const Register = (props) => {

  const dispatch = useDispatch();
  const [id, setId] = useState("");
  const [pw, setPw] = useState("");
  const [pwC, setPwC] = useState("");

  const idChangeHandler = (e) => {
setId(e.currentTarget.value);
}
  const pwChangeHandler = (e) => {
setPw(e.currentTarget.value);
}

  const pwCChangeHandler = (e) => {setPwC(e.currentTarget.value);
}

  const submitHandler = (e) => {
    e.preventDefault()
    
const data = {
 name: id,
 password: pw
 }
    dispatch(register(data))
      .then(res => {
        //redux로 가져올 경우 payload, axios로 바로 가져올 경우 data
        if(res.payload.success){
          props.history.push("/");
        } else { 
          alert(res.payload.err);
        }
     })
}

  return (
    <form onSubmit={submitHandler}>
       <label>
아이디</label>
       <input type="text" value={id} onChange={idChangeHandler}/>
       <label>
비밀번호
</label>
       <input type="password" value={pw} onChange={pwChangeHandler}/>
       <label>
비밀번호 확인
</label>
       <input type="password" value={pwC} onChange={pwCChangeHandler}/>

       <button>SIGN UP</button>
    </form>
  )
}

먼저 form을 작성한다. React에서는 hook의 useState를 이용해서 input의 값을 조정한다.

input value에 state를 넣고 onChange가 일어날 경우, event.currentTarget.value로 setState 한다.

그렇게 상태 값을 가지고 있다가, submit을 할 때 다음 단계에 구현할 action을 dispatch를 이용해 호출해서 로직을 처리한다.

Redux action, reducer와 axios로 데이터 통신

//type 정의
export const REGISTER = 'register'
//action 정의
import axios from 'axios';
import {REGISTER} from './actionType'

export function register(data) {
  const req = axios.post('user/register', data)
    .then(res => res.data);
  return { type: REGISTER, payload: req }
}
//reducer 정의
import {REGISTER} from '../action/actionType'

export default function (state = {}, action){
  switch(action.type){
    case REGISTER:
      return {...state, register: action.payload}
    default:
      return state;
  }
}

redux로 상태를 관리하기 위해선 type => action => reducer 순으로 정의해야한다.

먼저 정의한 type을 이용해 action을 정의하는데 action은 state를 변경하기 위한 처리를 하는 곳이다. 회원가입에서는 client에서 데이터를 받아 server로 전달해야 하므로 axios를 이용해 post방식으로 전송한다. 그리고 그 결과 중의 data부분만 request에 담아 payload로 반환한다.

reducer는 action이 발생하는 것을 먼저 감지하여, action 처리 후의 payload값을 받아 state를 변화시킨다.

이 때 중요한 건 state는 불변해야 하므로, spread operator로 기존의 state를 그대로 가져오고 더할 부분만 뒤에 추가하는 것이다.

이렇게 하면 회원가입 로직은 프론트와 백 모두 구현 완료이다.

index.js에서 store와 provider를 구현은 지금 주제보다 더 깊이 정리해야하므로 여기까지만 정리해야겠다.

더 공부해볼 것

  1. spread operator
  2. redux with hooks (useDispatch)

Leave a comment

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다