과거 프로그래밍 자료들/React

React로 좋아요 버튼 누르기(1) - mongoDB users에 정보 담기

평부 2022. 5. 26. 16:03

* '따라하며 배우는 노드, 리액트 시리즈 - 쇼핑몰 사이트 만들기' 강의 참고

* react -> node.js로 이미지 및 정보 저장하기

* mongoDB에 저장하는 것까지 확인

 

* 강의에서는 Cart(결제) 내용이지만, 복습 차원으로 진행하는 글이기에 [좋아요] 버튼을 누르는 것으로 변경

 

 

 

* 상황 

* 좋아요(♥)를 누를 경우 mongoDB users에 정보가 담김

* 이미 좋아요 버튼을 누른 경우 -> 1에서 고정

 

 

 

[Client]

DataInfo.js

 

import React, { useState, useEffect } from "react";
import { Descriptions, Button } from "antd";
import { useDispatch } from "react-redux";
import { HeartTwoTone } from "@ant-design/icons";
import { addToHeart } from "../../../../_actions/user_action";

function DataInfo(props) {
  const [Data, setData] = useState({});

  useEffect(() => {
    setData(props.detailData);
    // console.log(props.datailData);
  }, [props.detailData]);

  const dispatch = useDispatch();
  const clickHandler = () => {
    //상품에 대한 id, 갯수, 날짜 정보(언제 넣었는지) 정보
    dispatch(addToHeart(props.detailData._id));
  };

  return (
    <div>
      <Button
        type="primary"
        shape="circle"
        icon={<HeartTwoTone />}
        style={{
          position: "relative",
          left: "150px",
          top: "27px",
          fontSize: "20px",
        }}
        onClick={clickHandler}
      />

      <Descriptions title="상품 Product Info" bordered>
        <Descriptions.Item label="Price">{Data.title}</Descriptions.Item>
        <Descriptions.Item label="price">{Data.price}</Descriptions.Item>
        <Descriptions.Item label="Seasons">{Data.seasons}</Descriptions.Item>
        <Descriptions.Item label="Description">
          {Data.description}
        </Descriptions.Item>
      </Descriptions>
    </div>
  );
}

export default DataInfo;

 

 

[Client]

_actions/types.js & _actions/user_action.js

 

//types.js
export const ADD_TO_HEART = "add_to_heart";


//user_action.js
//addToHeart
export function addToHeart(_id) {
  let body = {
    dataId: _id,
  };

  //get 메소드는 body 부분 : dataToSubmit 필요 없음
  //USER_SERVER = '/api/user'
  const request = axios
    .post(`${USER_SERVER}/addToHeart`, body)
    .then((response) => response.data);

  return {
    type: ADD_TO_HEART,
    payload: request,
  };
}

 

 

[Client]

user_reducer.js

 

import {
  ADD_TO_HEART,
} from "../_actions/types";

export default function (state = {}, action) {
  switch (action.type) {
    case ADD_TO_HEART:
      return {
        ...state,
        userData: {
          ...state.userData,
          heart: action.payload,
        },
      };

    default:
      return state;
  }
}

 

 

[Server]

User.js

 

const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const saltRounds = 10;
const jwt = require("jsonwebtoken");

const userSchema = new mongoose.Schema({
  name: {
    type: String,
    maxlength: 50,
  },
  email: {
    type: String,
    trim: true,
    unique: 1,
  },
  password: {
    type: String,
    minlength: 5,
  },
  lastname: {
    type: String,
    maxlength: 50,
  },
  role: {
    type: Number,
    default: 0,
  },
  cart: {
    type: Array,
    default: [],
  },
  history: {
    type: Array,
    default: [],
  },
  image: String,
  token: {
    type: String,
  },
  tokenExp: {
    type: Number,
  },
  //추가
  heart: {
    type: Array,
    default: [],
  },
  //추가
  heartHistory: {
    type: Array,
    default: [],
  },
});


const User = mongoose.model("User", userSchema);

module.exports = { User };
// module.exports = mongoose.model("User", userSchema);

 

 

[Server]

routes/user.js

 

//${USER_SERVER}/addToHeart
router.post("/addToHeart", auth, (req, res) => {
  //유저 정보 찾기
  User.findOne({ _id: req.user._id }, (err, userInfo) => {
    let overlap = false;

    console.log(userInfo);

    //유저 정보 중 좋아요 값을 넣을 곳 있는지
    userInfo.heart.forEach((item) => {
      if (item.id == req.body.dataId) {
        overlap = true;
      }
    });

    //좋아요가 이미 눌러져 있다면 quantity: 0
    if (overlap) {
      User.findOneAndUpdate(
        { _id: req.user._id, "heart.id": req.body.dataId },
        { $inc: { "heart.$.quantity": 0 } },
        { new: true }, //Redux-Devtool 확인 시 반드시 넣을 것
        (err, userInfo) => {
          if (err) return res.json({ success: false, err });
          res.status(200).json(userInfo.heart);
        }
      );
    } else {
      //좋아요가 아직 눌러져있지 않다면 quantity: 1
      User.findOneAndUpdate(
        { _id: req.user._id },
        {
          $push: { //heart에 값 넣기
            heart: {
              id: req.body.dataId,
              quantity: 1,
              date: Date.now(),
            },
          },
        },
        { new: true }, //Redux-Devtool 확인 시 반드시 넣을 것
        (err, userInfo) => {
          if (err) return res.json({ success: false, err });
          res.status(200).json(userInfo.heart);
        }
      );
    }
  });
});

 

 

* 결과 : 처음 좋아요를 누른 경우

 

 

 

* 결과 : 두 번째 좋아요를 누른 경우

 

 

* $inc : 단독으로 사용하지 않고 특수값 변경

* 출처 : (https://www.mongodb.com/docs/v4.4/reference/operator/update/inc/?_ga=2.69508304.1718093744.1653538507-319990480.1653538504&_gac=1.208930342.1653539924.EAIaIQobChMIwvfTg-7t9wIVy8CWCh2ZkgT5EAAYASAAEgIQ2PD_BwE)

 

 

 

* $push : 원래 값에서 정보 추가

* 출처 : (https://www.mongodb.com/docs/v5.0/reference/operator/update/push/?_ga=2.104314048.1718093744.1653538507-319990480.1653538504&_gac=1.47378451.1653539924.EAIaIQobChMIwvfTg-7t9wIVy8CWCh2ZkgT5EAAYASAAEgIQ2PD_BwE)