REACT 댓글 추가 삭제 기능 + 좋아요 버튼

import React, { Component } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faHeart as heartInactive } from '@fortawesome/free-regular-svg-icons';
import { faHeart as heartActive } from '@fortawesome/free-solid-svg-icons';
import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
import LikeButton from '../../../components/LikeButton/LikeButton';
import './Review.scss';

class Review extends Component {
  constructor() {
    super();
    this.maxId = 3;
    this.state = {
      userValue: '',
      textValue: '',
      comments: [
        {
          id: 1,
          userName: 'jeju',
          comment: '비자림이 그저 forest?',
          isLiked: false,
        },
        {
          id: 2,
          userName: 'dabin',
          comment: '흑임자 쑥 프라푸치노 드세요',
          isLiked: false,
        },
        {
          id: 3,
          userName: 'darling',
          comment: '멍멍멍멍 왈왈왈왈',
          isLiked: false,
        },
    };
  }
  
  //리뷰 입력 창 변화 감지시 value를 state에 저장, 비구조화 할당 적용
  getValue = e => {
    const { value, name } = e.target;
    this.setState({
      [name]: value,
    });
  };

  addReview = e => {
    const { userValue, textValue } = this.state;
    
    //참조형에서의 얕은 복사: 서로 같은 주솟값을 바라보기 때문에 원본도 수정됨
    let newComments = this.state.comments;
    this.maxId = this.maxId + 1;
    //이름+내용 존재할 때만 add review
    if (userValue !== '' && textValue !== '') {
      newComments = newComments.concat({
        id: this.maxId,
        userName: this.state.userValue,
        comment: this.state.textValue,
        isLiked: false,
      });
      this.setState({
        comments: newComments,
        userValue: '',
        textValue: '',
      });
    } else {
      alert('이름과 댓글 모두 입력해주세요 ♡◟(●•ᴗ•●)◞♡');
    }
  };
  //input창에서 enter키를 눌렀을 때에도 addReview가 동작
  addReviewByEnter = e => {
    if (e.key === 'Enter') {
      this.addReview();
      e.target.value = '';
    }
  };

  removeReview = id => {
    //친절하게 삭제 여부를 다시 확인받기! 
    if (window.confirm('진짜 삭제하고 싶어요?( •_ •̥ ˳ ˳ )')) {
      const { comments } = this.state;
      //id는 인자로 전달받은 댓글추가 당시 userValue
      const nextComments = comments.filter(comment => comment.id !== id);
      this.setState({
        comments: nextComments,
      });
    }
  };
//좋아요 버튼은 isLiked를 데이터로 저장할 수 있어야 한다. 
//댓글 좋아요 버튼 클릭시 id가 일치하는 댓글을 찾아 그 댓글의 isLiked만 변경한다.
  likeButtonClicked = id => {
    const { comments } = this.state;
    const likedComments = comments.map(comment => {
      if (comment.id === id) {
        comment.isLiked = !comment.isLiked;
      }
      return comment;
    });
    this.setState({ comments: likedComments });
  };
    
  render() {
    return (
      <>
        <div className="Review">
          <h3 className="reviewTitle">리뷰</h3>
          <div className="comments">
            <ul className="commentsBox">
              {this.state.comments.map((review, id) => {
                return (
                  <li className="addedReview" key={id}>
                    <p className="addedName">{review.userName}</p>
                    <p className="addedComment">{review.comment}</p>
                    <i
                      onClick={() => this.likeButtonClicked(review.id)}
                      className="LikeButton commentLikeButton"
                    >
                      <FontAwesomeIcon
                        icon={review.isLiked ? heartActive : heartInactive}
                        className={review.isLiked ? 'fillHeart' : ''}
                      />
                    </i>
                     //인자를 전달하기 위해 화살표 함수 사용
                    <i onClick={() => this.removeReview(review.id)}>
                      <FontAwesomeIcon icon={faTrashAlt} key={review.id} />
                    </i>
                  </li>
                );
              })}
            </ul>
          </div>
          <div className="pushBox">
            <input
              className="userNameInput"
              name="userValue"
              type="text"
              value={this.state.userValue}
              placeholder="name"
              required
              onChange={this.getValue}
              onKeyPress={this.addReviewByEnter}
            />
            <input
              className="reviewText"
              name="textValue"
              type="text"
              value={this.state.textValue}
              placeholder="리뷰를 입력해주세요"
              required
              onChange={this.getValue}
              onKeyPress={this.addReviewByEnter}
            />
            <button className="push" onClick={this.addReview}>
              POST
            </button>
          </div>
        </div>
      </>
    );
  }
}

export default Review;

디테일 페이지는 하나의 컴포넌트 안에서 like button을 처리했지만, list page에서는 부모와 자식 컴포넌트를 넘나들며 구현해야 했다.

//List.js
//자식 컴포넌트에 전달
{coldbrew.map(data => {
  return (
    <CoffeeCard
      key={data.id}
      id={data.id}
      title={data.title}
      img={data.img}
      isLiked={data.isLiked}
      likeButtonClicked={() =>
        this.likeButtonClicked(coldbrew, data.id)
      }
    />
  );
})}

//CoffeeCard.js
//props로 전달받은 데이터를 적용
<div className="CoffeeCard">
  <div className="coffeeImgWithIcon">
    <img
      className="coffeeImg"
      alt={this.props.title}
      src={this.props.img}
      onClick={this.moveToDetailPage}
    />
    <label className="listLikeButton">
      <i onClick={this.props.likeButtonClicked} className="LikeButton">
        <FontAwesomeIcon
          icon={this.props.isLiked ? heartActive : heartInactive}
          className={this.props.isLiked ? 'fillHeart' : ''}
        />
      </i>
    </label>
  </div>
  <p className="listPageCoffeeName">{this.props.title}</p>
</div>

좋은 웹페이지 즐겨찾기