본문 바로가기

TIL/React

React) 백엔드와 연동하여 좋아요 기능 구현하기 <TIL_2022_07_31>

위 그림과 같이 각 게시글마다 좋아요를 누를 수 있게 하는 기능을 구현하고자 한다.

 

Likes 테이블 생성, 관계 설정

한 명의 유저가 여러 개의 게시글에 좋아요를 누를 수 있고, 한 개의 게시글에도 마찬가지로 여러명의 좋아요가 기록될 수 있으므로,

user와 questions 테이블은 서로 N : M(다 대 다) 관계를 갖는다.

 

이들을 이어줄 인자값으로 likes 테이블을 생성한다.

 

// models/likes.js
const Sequelize = require("sequelize");
module.exports = function (sequelize, DataTypes) {
  return sequelize.define(
    "likes",
    {
      id: {
        type: DataTypes.INTEGER,
        allowNull: false,
        primaryKey: true,
        autoIncrement: true,
      },
    },
    {
      sequelize,
      tableName: "likes",
      charset: "utf8mb4",
      collate: "utf8mb4_general_ci",
      timestamps: false,
    }
  );
};

// models/init-models.js
questions.belongsToMany(user, {
    as: "likers",
    through: likes,
    foreignKey: "questionId",
  });
  user.belongsToMany(questions, {
    as: "likedQuestions",
    through: likes,
    foreignKey: "userId",
  });

위와 같이 models 폴더에 likes.js를 추가하고, id값만 정의해준다.

그리고 테이블 간 관계를 정의하는 init-models.js에서 questionId, userId를 각각 foreignKey로 하여 likes 테이블로 questions, user두 테이블을 이어주는 N:M 관계를 선언한다.

 

위와 같이 likes 테이블이 생성되었다.

(이후 이 likes 테이블을 이용해 '해당 게시물에 좋아요 누른 사람들의 정보 조회', '해당 유저가 좋아요 누른 게시글들의 정보 조회' 등의 기능을 구현할 수 있을 것이다.)

 

 

 

이제 좋아요 기능을 구현해야 하는데, 유저가 좋아요를 중복해서 누르지 못하도록 하는 기능을 구현하는 데에 위의 likes 테이블이 쓰인다.

 

// questions.ctrl.js
upvoteQuestion: async (req, res) => {
    const questionId = req.params.questionId;
    const question = await models.questions.findOne({
      where: { id: questionId },
    });
    // 유저id를 클라이언트에서 req.body에 받아온다
    const userId = req.body.userId;
    // likes 테이블에서 유저의 좋아요 중복 여부를 체크한다
    const likes = await models.likes.findOne({
      where: {
        questionId: questionId,
        userId: userId,
      },
    });
    // 좋아요 중복 여부에 따라 true or false를 response로 보낸다
    if (!likes) {
      await question.update({
        upvote: question.upvote + 1,
      });
      await models.likes.create({
        questionId: questionId,
        userId: userId,
      });
      res.send(true);
    } else {
      res.send(false);
    }
  },

 

이후 위처럼 서버에서 보낸 response 값(true or false)을 이용해 클라이언트에서 로직을 구현한다.

// UserDetail.jsx
const onClickLike = async (questionId) => {
    if (!isLogged) {
      alertAuth();
    } else {
      await axios
        .patch(`${BASE_URL}/questions/upvote/${questionId}`, {
          userId: loginData.id,
        })
        // api에서 받은 값을 이용하여 로직 구현
        .then((res) => {
          if (!res.data) {
            alert("이미 추천하셨습니다.");
          } else {
            window.location.reload();
          }
        });
    }
  };

 

느낀점

  • patch 요청에 대한 response 값을 클라이언트에서 받아 와서 활용하는 것은 처음 구현해본다. patch나 post에서도 클라이언트로 response를 보내서 활용할 수 있다는걸 명심하자.