MySQL

React, MySQL 12일차 (좋아요 누르기)

수연 (Suyeon) 2023. 10. 30. 01:04
반응형

PedroTech님의 풀스택 강의 12일 차를 참고했습니다.

 

📌 Likes 테이블 생성하기

// ./server/models/Likes.js

// Likes 테이블 생성합니다.
module.exports = (sequelize, DataTypes) => {
  const Likes = sequelize.define("Likes");

  return Likes;
};
// ./server/models/Post.js

module.exports = (sequelize, DataTypes) => {
  const Posts = sequelize.define("Posts", {...
  });

  Posts.associate = (models) => {
    Posts.hasMany(models.Comments, {...
    });

	// Post테이블의 id와 Likes 테이블을 1:N 관계로 생성합니다.
    Posts.hasMany(models.Likes, {
      onDelete: "cascade",
    });
  };
  return Posts;
};
// ./server/models/Users.js

module.exports = (sequelize, DataTypes) => {
  const Users = sequelize.define("Users", {...
  });

  // Users의 id와 Likes 테이블을 1:N 관계로 생성합니다.
  Users.associate = (models) => {
    Users.hasMany(models.Likes, {
      onDelete: "cascade",
    });
  };
  return Users;
};

Likes 테이블을 생성한 뒤, Posts 테이블의 idUsers 테이블의 id1:N 관계로 연결해 줍니다.
테이블을 생성할 때는 서버 연결을 끊는 것이 좋습니다.

 

 

 

📌 Likes router 생성하기

// ./server/routes/Likes.js

router.post("/", validateTocken, async (req, res) => {
  const { PostId } = req.body;
  const UserId = req.user.id;

  // PostId와 UserId가 동일한 데이터 1개만 가져옵니다.
  const found = await Likes.findOne({
    where: { PostId: PostId, UserId: UserId },
  });

  // 좋아요를 눌렀을 때 만약 정보가 없다면 새로 추가하고,
  // 이미 정보가 있다면 해당 데이터를 삭제해줍니다.
  if (!found) {
    await Likes.create({ PostId: PostId, UserId: UserId });
    res.json({ liked: true });
  } else {
    await Likes.destroy({
      where: { PostId: PostId, UserId: UserId },
    });
    res.json({ liked: false });
  }
});

module.exports = router;
// ./server/index.js

// http://localhost:1234/likes를 호출하면 Likes router가 작동되도록 합니다.
const likesRouter = require("./routes/Likes");
app.use("/likes", likesRouter);
변수 설명(Likes.js)
1. PostId
: 좋아요를 누른 Post의 id값을 가지고 있습니다.
2. UserId
: 좋아요를 누른 사용자의 id값을 가지고 있습니다.
3. found
: Likes 테이블에서 조건에 맞는 데이터를 저장하고 있습니다.

조건문 설명(Likes.js)
1. if(!found)
: 좋아요를 누른 정보가 없다면 Likes 테이블에 데이터를 추가해 주고, liked를 true로 변경 후 결과로 반환합니다.
2. else
: 이미 좋아요를 눌렀다면 Likes 테이블에서 해당 데이터를 삭제한 뒤, liked를 false로 변경 후 결과로 반환합니다.

 

 

 

📌 좋아요 버튼과 함수 생성하기

// ./client/src/pages/Post.js

const { Posts, Likes } = require("../models");

// Likes 데이터를 포함해서 Posts 테이블의 데이터를 가져오도록 합니다.
// 1:N 관계로 연결되어 있기 때문에 알맞게 데이터를 가져올 수 있습니다.
router.get("/", async (req, res) => {
  const listOfPosts = await Posts.findAll({ include: [Likes] });
  res.json(listOfPosts);
});
// ./client/src/pages/Home.js

import React from "react";
import axios from "axios";
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";

function Home() {
  const [listOfPosts, setListOfPosts] = useState([]);
  let navigate = useNavigate();

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

  // 좋아요 버튼을 클릭했을 때 호출될 함수입니다.
  const likeAPost = (postId) => {
    axios
      .post(
        "http://localhost:3001/likes",
        { PostId: postId },
        { headers: { accessTocken: localStorage.getItem("accessTocken") } }
      )
      .then((response) => {
        setListOfPosts(
          listOfPosts.map((post) => {
            if (post.id === postId) {
              if (response.data.liked) {
                return { ...post, Likes: [...post.Likes, 0] };
              } else {
                const likesArray = post.Likes;
                likesArray.pop();
                return { ...post, Likes: likesArray };
              }
            } else {
              return post;
            }
          })
        );
      });
  };

  return (
    <div>
      {listOfPosts.map((value, key) => {
        return (
          <div className="posts" key={key}>
            <div className="title">...
            </div>
            <div>...
            </div>
            <div className="footer">
              {value.username}
              {/*
                좋아요 버튼을 생성합니다.
              */}
              <div className="likeContainer">
                <button
                  type="button"
                  className="likeBtn"
                  onClick={() => {
                    likeAPost(value.id);
                  }}
                >
                  Like
                </button>
                <label>{value.Likes.length}</label>
              </div>
            </div>
          </div>
        );
      })}
    </div>
  );
}

export default Home;
좋아요 함수 설명(Home.js)
1. axios.post("경로", {PostId:~}, {header: ~})
: 지정된 경로로 PostId와 header 이 데이터들을 전달합니다.
2. setListOfPosts(~): 좋아요를 누른 결과를 바로 적용되도록 하기 위해 활용했습니다.
3. if (post.id === postId): listOfPosts에 있는 포스트의 id와 동일한지 확인하고 liked의 상태에 따라 LIkes에 적절한 값을 전달해 줍니다.
    - if (response.data.liked): 처음 좋아요를 눌렀을 때 post.Likes에 원래 데이터(...post.Likes)와 0을 추가해서 좋아요가 1개 증가할 수 있도록 합니다.
    - else: 이미 좋아요를 누른 상태라면 post.Likes의 데이터를 가져온 뒤 1개를 삭제해서 좋아요 수가 하나 줄어들 수 있도록 합니다.

4. else: 좋아요 버튼을 누르지 않은 다른 post이기 때문에 그대로 결과를 반환합니다.

 

 

 

📌 결과

좋아요를 누르기 전 화면입니다.

 

좋아요를 누른 화면입니다.

 

 

 

📌 느낀 점

커뮤니티 페이지를 구현할 계획이었는데 좋아요 버튼은 따로 테이블을 생성하는 게 좋은지 고민이 많았는데 이런 식으로 하면 깔끔하게 관리할 수 있을 것 같아서 좋은 방법을 배운 것 같아 아주 기쁩니다!!

무료로 이렇게 필요한 기능들을 배울 수 있다는 것에 참 감사한 마음입니다. PedroTech님..! 감사합니다!

728x90