DevConnector 프로젝트 02 - 내겐 조금 생소한 코드 - 클라이언트

|

DevConnector 프로젝트 02 - 내겐 조금 생소한 코드 - 클라이언트

setFormData({ …formData, [e.target.name]: e.target.value });

const [formData, setFormData] = useState({
  name: '',
  email: '',
  password: '',
  password2: '',
});

const { name, email, password, password2 } = formData;

const onChange = (e) =>
  setFormData({ ...formData, [e.target.name]: e.target.value });

<input
  type='text'
  placeholder='Name'
  name='name'
  value={name}
  onChange={(e) => onChange(e)}
  required
/>;
  • 위의 코드에서 눈여겨 봐야할 것은 [e.target.name]: e.target.value 이다.
    es6 비구조화 할당문법을 사용하여 코드를 간소화시켰다.

클라이언트에서 axios를 활용해 서버에 데이터 전송 및 데이터 받아오기

const onSubmit = async (e) => {
  e.preventDefault();
  if (password !== password2) {
    console.log('패스워드가 일치하지 않습니다.');
  } else {
    const newUser = {
      name,
      email,
      password,
    };
    try {
      const config = {
        headers: {
          'Content-Type': 'Application/json',
        },
      };

      const body = JSON.stringify(newUser);

      const res = await axios.post('/api/users', body, config);
      console.log(res.data);
    } catch (err) {
      console.error(err.response.data);
    }
  }
};
  • onSubmit부분을 주목하자.
    axios를 이용해서 클라이언트에서 데이터를 전송 및 받아오는 코드에는 .then .catch 기타 등등 다양한 코드가있지만, 여기서는 async await 를 활용해 try catch문으로 데이터 응답 및 에러를 처리해주었다.
    에러메시지를 받아오는게 좀 생소했는데, 직접 console.log(err)를 찍어본 결과, err는 객체에는 헤더 및 기타 등등의 여러 데이터가 담겨있는데 그중에서 서버에서 에러메시지를 전달해주는 response객체안의 data가있었다.

    받아올 때는 마찬가지로 res.data로 받아온다.

이후 리덕스로 대체

DevConnector 프로젝트 01 - 내겐 조금 생소한 코드 - 서버

|

DevConnector 프로젝트 01 - 내겐 조금 생소한 코드 - 서버

express에 bodyParser가 통합됬다?

  • 유데미 강의에서 서버단을 설정하고있는데 조금 생소한 코드가 등장했다.
    오래전 노마드코더 유튜브 클론 코딩 강의에서 express를 사용할때는 bodyParser를 명시해줬는데, 이제는 express가 통합되면서 명시해주지 않아도 되나보다.
const express = require('express');
const connectDB = require('./config/db');

const app = express();

// Connect Database
connectDB();

// Init Middleware
// bodyParser 미들웨어의 여러 옵션 중에 하나로,
// bodyParser가 express에 흡수되서 따로 명시해주지않아도된다.
app.use(express.json({ extended: false }));

app.get('/', (req, res) => res.send('API Running'));

// Define Routes
app.use('/api/users', require('./routes/api/users'));
app.use('/api/auth', require('./routes/api/auth'));
app.use('/api/profile', require('./routes/api/profile'));
app.use('/api/posts', require('./routes/api/posts'));

const PORT = process.env.PORT || 5000;

app.listen(PORT, () => console.log(`Server started on PORT ${PORT}`));

express-validator?

  • express-validator는 유효성을 검사한다고한다. Ex)회원가입시 중복된 닉네임 혹은 이메일 검사 등등..

  • 그럼 사용은 어떤식으로 할까?

    참고자료

// users.js
const express = require('express');
const router = express.Router();
const { check, validationResult } = require('express-validator');

// @route   POST api/users
// @desc    Register user
// @access  Public
router.post(
  '/',
  [
    check('name', 'Name is required').not().isEmpty(),
    check('email', 'Please include a valid email').isEmail(),
    check(
      'password',
      'Please enter a password with 6 or more characters'
    ).isLength({ min: 6 }),
  ],
  (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }
    res.send('User route');
  }
);

module.exports = router;

express-validator 포인트

포인트 1

check('name', 'Name is required').not().isEmpty(),
  • 'Name is required' 이런식으로 중간에 에러메시지를 작성해줄수 있다.

포인트 2

(req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(400).json({ errors: errors.array() });
  }
  res.send('User route');
};
  • const errors = validationResult(req);로 유효성 검사값을 변수에 집어넣어 현재 상태값을 응답해줄 수 있는데, 유효한 값이 아니면 에러메시지가 다음처럼 나타난다.
views
포스트맨에서 email, password 유효성 실패 메시지를 출력해주는 모습..


  • 반대로 유효한 값을 입력하면 설정해줬던 res.send('User route'); 메시지가 잘 나타난다.
views
포스트맨에서 email, password성공시 메시지를 출력해주는..

javascript공부를 들어가기에 앞서 마음가짐

|

효율적으로 공부하기위한 마음가짐

드림코드 엘림님의 가짐을 옮겨왔습니다.

우리는 모든 것을 다 알지 못한다.

  • 다양한 것을 다 알지 못한다고해서 너무 좌절하거나, 혹은 한번에 모든 것을 다 공부하려고하면 금방 지친다.

문제 해결능력 연습이 중요하다.

  • 어떻게 효율적으로 배울 수 있을지를 고민하라.

  • 모든것을 외우려고하지말고 이해하면서 어떻게 내가 문제를 해결 할 수있는지, 어떻게 검색하는지, 내가 모르는것을 어떻게 알아가는지가 중요하다.

능동적으로 학습하자

  • 눈으로만 보지말고, 직접 코드를 작성해보라.

이해를 먼저 하고, 노트를 정리하자

  • 이것이 왜 이렇게 동작하는지 그 원리를 이해하면 따로 외우지 않아도된다.

    개인적으로 마지막 이해를 먼저 하고,노트를 정리하자는 부분이 너무나 마음에 와닿는다.

nodejs 파일 업로드 - multer 이미지 지우기

|

nodejs 파일 업로드 - multer 이미지 지우기

서버에 저장된 이미지를 지우는 것이아닌, 서버에 올라가기전 미리보기 이미지 UI에있는 이미지를 지우는 것입니다!!

클릭시 이미지 지우기

  • indexOf를 활용해 각각의 index를 가져온다.

  • splice를 활용해준다.

    • filter를 사용해도 될듯하다.
  const deleteHandle = (image) => {
    const currentIndex = Images.indexOf(image);
    // console.log(currentIndex);
    let newImages = [...Images];
    newImages.splice(currentIndex, 1);

    setImages(newImages); 
    // 내가 클릭한 이미지의 index 번호~1까지 지워주겠다는뜻,
    // Ex) index 번호 0을 클릭했다면 0부터1까지 지우는거니, 하나만 지움
    // Ex2) index 번호 2를 클릭했다면 2부터3까지 지우는거니, 하남나 지움
  };

전체 코드

  • Front
import React, { useState } from 'react';
import Dropzone from 'react-dropzone';
import { Icon } from 'antd';
import axios from 'axios';

const FileUpload = () => {
  // 업로드할 이미지들을 담는 용도
  const [Images, setImages] = useState([]);

  const dropHandle = async (files) => {
    let formData = new FormData();

    const config = {
      header: { 'content-type': 'multipart/form-data' },
    };
    formData.append('file', files[0]);

    axios.post('/api/product/image', formData, config).then((response) => {
      if (response.data.success) {
        // console.log(response.data);
        setImages([...Images, response.data.filePath]);
      } else {
        alert('파일을 저장하는데 실패했습니다.');
        console.log(response.data.err);
      }
    });
  };

  const deleteHandle = (image) => {
    const currentIndex = Images.indexOf(image);
    // console.log(currentIndex);
    let newImages = [...Images];
    newImages.splice(currentIndex, 1);

    setImages(newImages); 
    // 내가 클릭한 이미지의 index 번호~1까지 지워주겠다는뜻,
    // Ex) index 번호 0을 클릭했다면 0부터1까지 지우는거니, 하나만 지움
    // Ex2) index 번호 2를 클릭했다면 2부터3까지 지우는거니, 하남나 지움
  };

  return (
    <div style=>
      <Dropzone onDrop={dropHandle}>
        {({ getRootProps, getInputProps }) => (
          <div
            style=
            {...getRootProps()}
          >
            <input {...getInputProps()} />
            <Icon type='plus' style= />
          </div>
        )}
      </Dropzone>

      {/* 이미지를 뿌려주는 UI */}
      <div
        style=
      >
        {Images.map((image, index) => (
          <div onClick={() => deleteHandle(image)} key={index}>
            <img
              style=
              src={`http://localhost:5000/${image}`}
            />
          </div>
        ))}
      </div>
    </div>
  );
};

export default FileUpload;

결과물

views
클릭시, 미리보기 이미지를 삭제해주는 모습.

nodejs 파일 업로드 - multer 모듈

|

nodejs 파일 업로드 - multer 모듈

multer이란?

multer은 한국번역이 잘 되어있으니 한번 살펴보시기바랍니다.자료
하지만 제가 듣고있는 강의의 강사는, 자료에 나와있는 내용은 반토막 설명이라고합니다. 어떻게 접근하는지 더 자세히 알고싶으시면 console.log찍어보면서 사용하시는걸 추천합니다.

  • multer란 파일 업로드를 위해 사용되는 multipart/form-data를 다루기 위한 node.js 의 미들웨어이다.

  • Multer는 multipart (multipart/form-data)가 아닌 폼에서는 동작하지 않는다.

multer 기본 설명서

github multer에서 따온 코드를 토대로 간단히 설명합니다.

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, '/tmp/my-uploads');
  },
  filename: function (req, file, cb) {
    cb(null, file.fieldname + '-' + Date.now());
  },
});

var upload = multer({ storage: storage });
  • destination: 어디에 파일이 저장되는지를 얘기해준다. 나는 루트디렉토리에 uploads폴더를 만들어 이 안에 모든 이미지파일들이 들어가게 해줄것임

  • filename: uploads/폴더안에 파일이 저장될때 어떤 이름으로 저장될것인지 설정해준다.

multer 기본 예제

Front

const dropHandle = (files) => {
  let formData = new FormData();

  const config = {
    header: { 'content-type': 'multipart/form-data' },
  };
  formData.append('file', files[0]);

  axios.post('/api/product/image', formData, config).then((response) => {
    if (response.data.success) {
      // 작업 성공시 로직 
      console.log(response.data);
    } else {
      alert('파일을 저장하는데 실패했습니다.');
    }
  });
};

Server

  • index.js
app.use('/api/product', require('./routes/product'));
  • server>routes>product
var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads/');
  },
  filename: function (req, file, cb) {
    cb(null, `${Date.now()}_${file.originalname}`);
  },
});

var upload = multer({ storage: storage }).single('file');

router.post('/image', (req, res) => {
  // 가져온 이미지를 저장해주면 됨
  upload(req, res, (err) => {
    if (err) {
      return req.json({ success: false, err });
    }
    return res.json({
      success: true,
      filePath: res.req.file.path,
      fileName: res.req.file.filename,
    });
  });
});
// filePath:res.req.file.path 어디에 파일이 저장되있는지 path(위치)를 가져올수있다.
// fileName: 저장된 파일의 이름을 가져올 수 있다.
module.exports = router;

이미지를 업로드해보자(기초)

views
업로드성공시 콘솔에 찍히는 모습.
이미지는 uploads폴더안에 저장된다.

파일 업로드 작업 마무리

업로드한 파일을 화면에 뿌려주는 작업입니다.

  • 핵심은 useState와 mpa을통해 데이터를 뿌려주는것이 핵심이다.

    Front

import React, { useState } from 'react';
import Dropzone from 'react-dropzone';
import { Icon } from 'antd';
import axios from 'axios';

const FileUpload = () => {
  // 업로드할 이미지들을 담는 용도
  const [Images, setImages] = useState([]);

  const dropHandle = async (files) => {
    let formData = new FormData();

    const config = {
      header: { 'content-type': 'multipart/form-data' },
    };
    formData.append('file', files[0]);

    axios.post('/api/product/image', formData, config).then((response) => {
      if (response.data.success) {
        // console.log(response.data);
        setImages([...Images, response.data.filePath]);
      } else {
        alert('파일을 저장하는데 실패했습니다.');
        console.log(response.data.err);
      }
    });
  };

  return (
    <div style=>
      <Dropzone onDrop={dropHandle}>
        {({ getRootProps, getInputProps }) => (
          <div
            style=
            {...getRootProps()}
          >
            <input {...getInputProps()} />
            <Icon type='plus' style= />
          </div>
        )}
      </Dropzone>

      {/* 이미지를 뿌려주는 UI */}
      <div
        style=
      >
        {Images.map((image, index) => (
          <div key={index}>
            <img
              style=
              src={`http://localhost:5000/${image}`}
            />
          </div>
        ))}
      </div>
    </div>
  );
};

export default FileUpload;

파일 업로드 작업 마무리 결과물

views
업로드 할 사진의 미리보기 이미지 작동 화면.