wontae

2st Project at Wecode! - Arket In Germany๐Ÿ‡ฉ๐Ÿ‡ช

๐Ÿ™Œ ๊ณตํ†ต์‚ฌํ•ญ

  • Git์„ ์‚ฌ์šฉํ•œ ํŒ€ ํ˜‘์—… ๊ณผ์ •
  • squash, rebase๋ฅผ ์ ์šฉํ•˜์—ฌ commit ๋‚ด์—ญ ๊ด€๋ฆฌ
  • Trello๋ฅผ ํ™œ์šฉํ•œ ์Šคํฌ๋Ÿผ ๋ฐฉ์‹ ์•„๋ž˜ ํ”„๋กœ์ ํŠธ ์ง„ํ–‰

๐Ÿ™Œ Front-end

  • React.js๋ฅผ ์ด์šฉํ•œ ํด๋ก 
  • CRA(create-react-app)๋ฅผ ์‚ฌ์šฉํ•œ ์ดˆ๊ธฐ ์„ธํŒ…
  • styled-components ํ™œ์šฉ
  • Redux๋ฅผ ์ด์šฉํ•œ ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ
  • Hooks๋ฅผ ์ด์šฉํ•œ ์ปดํฌ๋„ŒํŠธ ์ƒํƒœ ๊ด€๋ฆฌ
  • localStorage์™€ token์„ ์ด์šฉํ•œ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • react-router, query string, path๋กœ ๋™์  ๋ผ์šฐํŒ… ๊ตฌํ˜„
  • Code refactoring

๐Ÿ™Œ Back-end

  • Django๋ฅผ ์‚ฌ์šฉํ•œ ์ดˆ๊ธฐ ์„ธํŒ…
  • Aquery๋ฅผ ์ด์šฉํ•œ ๋ชจ๋ธ๋ง
  • Bcrypt๋ฅผ ์ด์šฉํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™”๋กœ ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • PyJWT
  • Mysql
  • Code refactoring

๐ŸŽ‰ ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„

  • 2020.10.05 ~ 2020.10.16

๐Ÿ›ธ ์‚ฌ์šฉ ๊ธฐ์ˆ 

Front-endReact
JavaScript
styled-components
Redux, react-redux
Git

Back-endAqueryTool
Python
Django
MySQL
PyJWT / Bcrypt
Git

๐Ÿš€ ๋‚ด๊ฐ€ ๋งก์€ ํŒŒํŠธ

Redux ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ

redux

cart.js
const ADD_TO_CART = 'cart/ADD_TO_CART';
const REMOVE_ITEM = 'cart/REMOVE_ITEM';
const RESET_CART_LIST = 'cart/RESET_CART_LIST';
const INCREASE_COUNT = 'cart/INCREASE_COUNT';
const DECREASE_COUNT = 'cart/DECREASE_COUNT';
const SET_TOTAL = 'cart/SET_TOTAL';
const GET_ITEMS = 'cart/GET_ITEMS';

export const addToCart = (item) => ({
    type: ADD_TO_CART,
    payload: item,
});

export const removeItem = (items) => ({
    type: REMOVE_ITEM,
    payload: items,
});

export const resetCartList = () => ({
    type: RESET_CART_LIST,
});

export const increaseCount = (items) => ({
    type: INCREASE_COUNT,
    payload: items,
});

export const decreaseCount = (items) => ({
    type: DECREASE_COUNT,
    payload: items,
});

export const setTotal = () => ({
    type: SET_TOTAL,
});

export const getItems = (items) => ({
    type: GET_ITEMS,
    payload: items,
});

const initialState = {
    totalPrice: 0,
    totalCount: 0,
    items: [],
};

const cart = (state = initialState, { type, payload }) => {
    switch (type) {
        case ADD_TO_CART:
            return updateItems(state, payload);
        case REMOVE_ITEM:
            return updateItems(state, payload);
        case RESET_CART_LIST:
            return {
                ...state,
                totalPrice: 0,
                totalCount: 0,
                items: [],
            };
        case INCREASE_COUNT:
            return updateItems(state, payload);
        case DECREASE_COUNT:
            return updateItems(state, payload);
        case GET_ITEMS:
            return updateItems(state, payload);
        default:
            return state;
    }
};

const updateItems = (state, payload) => {
    const { items } = state;
    const isArray = Array.isArray(payload);

    return isArray
        ? {
              ...state,
              items: [...payload],
              totalCount: payload.reduce((acc, { count }) => acc + count, 0),
              totalPrice: payload.reduce(
                  (acc, { count, price }) => acc + count * price,
                  0,
              ),
          }
        : {
              ...state,
              items: checkCartItems(items, payload),
              totalCount: state.totalCount + 1,
          };
};

const checkCartItems = (items, payload) => {
    const isAddedToCart = items.find((item) => item.id === payload.id);
    const AddedItem = (item) =>
        item.id === payload.id ? { ...item, count: item.count + 1 } : item;

    return isAddedToCart ? items.map(AddedItem) : [...items, payload];
};

export default cart;
  • ์•ก์…˜ ํ•˜๋‚˜๊ฐ€ ๋‹จ ํ•˜๋‚˜์˜ ๋™์ž‘๋งŒ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ๋งŽ์ด ๋‚˜๋ˆด์ง€๋งŒ ๊ฒฐ๊ตญ ๊ฐ™์€ ํ˜•ํƒœ์˜ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋œ๋‹ค๋ฉด ๊ตณ์ด ๋‚˜๋ˆ ์•ผํ–ˆ์„๊นŒ ์‹ถ๊ธฐ๋„ ํ•˜๋‹ค. ์–ด๋–ค ๊ฒƒ์ด ์ข‹์€ ๊ฒƒ์ธ์ง€ ๋” ์•Œ์•„๋ณด๊ณ  ์‹ถ๋‹ค. ๊ฐ€์žฅ ์ข‹์€ ์ตœ์ ํ™”๋Š” ๋ฌด์—‡์ผ๊นŒ?

๋ฉ”์ธ, ๋ฆฌ๋ทฐ ํŽ˜์ด์ง€ - ์ •์›ํƒœ ์ด๋„๊ธธ

  • AWS S3 ์™€ react-aws-s3 ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•œ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • ์œ ์ € ํ™•์ธ ํ›„ ๋ฆฌ๋ทฐ ์ˆ˜์ •/์‚ญ์ œ ๊ถŒํ•œ ๋ถ€์—ฌ
  • ๋ฆฌ๋ทฐ CRUD ๊ธฐ๋Šฅ ๊ตฌํ˜„

โœ ๊ธฐ์–ตํ•˜๊ณ  ์‹ถ์€ ์ฝ”๋“œ

ReviewForm.js/ImageUploader.js
// ReviewForm.js

import React, { useState, useRef } from 'react';
import S3 from 'react-aws-s3';

...

import {
  accessKeyId,
  secretAccessKey,
} from '../../../config';

export default function ReviewForm({ setReviewData }) {

...

  const handleFileChange = (e) => {
    const reader = new FileReader();
    const file = e.target.files[0];
    const newFileName = file.name;
    const config = {
      bucketName: 'uploadtestdb',
      dirName: 'photos',
      region: 'ap-northeast-2',
      accessKeyId,
      secretAccessKey,
    };
    const ReactS3Client = new S3(config);
    reader.onloadend = () => {
      setImagePreviewUrl(reader.result);
    };
    reader.readAsDataURL(file);
    ReactS3Client.uploadFile(file, newFileName)
      .then((data) => setImageUrl(data.location))
      .catch((err) => console.error(err));
  };

...

// ImageUploader.js

export default function ImageUploader({ handleFileChange, fileInput }) {
  return (
    <Form className="uploadSteps">
      <File>
        <FileInput
          ref={fileInput}
          onChange={handleFileChange}
          type="file"
          multiple
        />
      </File>
    </Form>
  );
}

...
  • react-aws-s3 ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•˜์—ฌ AWS S3 ์— ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ (์•„์ง AWS๊ฐ€ ์–ด๋ ต๋‹คใ… ใ… )

Reviews.js
import React, { useState } from 'react';
import styled, { keyframes } from 'styled-components';
import { API, reviewsTestToken } from '../../config';

export default function Reviews() {
  const [reviewData, setReviewData] = useState([]);

  const getReviewData = async () => {
    const requestOptions = {
      method: 'GET',
      headers: {
        Authorization: reviewsTestToken,
      },
    };
    const res = await fetch(`${API}/reviews`, requestOptions);
    const { data } = await res.json();
    setReviewData(data);
  };

  useEffect(() => {
    getReviewData();
  }, []);

  return (
    ...
  )
  • async, await ๋ฅผ ์ด์šฉํ•œ ๋ฐ์ดํ„ฐ ํ†ต์‹