React | '프립' 모티브 프로젝트 코드공유
프로젝트를 진행하며 협업, 새로운 기술 스택, 코드 작성 기술 등 다양한 배움이 있겠지만, 개인적으로 그 중에서 가장 큰 의미로 다가오는 건 실제로 직면한 문제를 해결하기 위해 다양한 방식을 고민해보고 그에 대한 해결책을 몸소 습득하게 되는 것이다.
2차 프로젝트를 진행하면서 많은 고민을 하게 만들었던 문제들과, 그 고민을 통해 얻은 결과를 정리해보고자 한다.
고민 no.1
[ PROBLEM ]
리뷰의 좋아요 기능을 구현하며 여러가지 문제를 맞이했는데, 그 중 가장 날 애먹였던 건 좋아요 버튼 클릭 시 모든 버튼의 숫자가 동기화 된다는 문제였다. map
으로 묶여있는 버튼들이라 어떤 버튼이 클릭되었는지 명확하게 파악할 수 없어 발생하는 문제라고 판단이 되었음에도, 어떻게 각 버튼에 접근해야할 지 감이 잡히지 않았다.
[ SOLUTION ]
긴 고민 끝에 멘토님에게 얻은 힌트.
- 리뷰 전체를
map
메소드를 활용하여 복사 - 클릭된 버튼의 id값과 같은 id를 가진 리뷰는 좋아요 수를 대체
- 나머지 버튼은 그대로 복사
reviews
state를 새롭게 정의하여 화면 재랜더링
얻은 힌트를 열심히 조합한 결과 아래와 같은 코드를 작성하였고, 성공적으로 기능 구현을 할 수 있었다.
export default function Review() {
const [reviews, setReviews] = useState([]);
function handleLikes(id) {
fetch(`${API.reviews}/review/like`, {
method: 'POST',
headers: {
Authorization: localStorage.getItem('token'),
},
body: JSON.stringify({
review_id: id,
}),
})
.then(res => res.json())
.then(res => {
const newData = reviews.map(review => {
if (id === review.id) {
return { ...review, likes: res.results.likes };
} else {
return review;
}
});
setReviews(newData);
});
}
return
<Likes onClick={() => {handleLikes(review.id);}} />
Key Point
- 새로운 변수를 선언하고
reviews
를map
하여 저장- 배열의 얕은 복사본을 만드는
스프레드 연산자
를 활용{...review, likes: res.results.likes}
의 형태로 사용할 수 있다는 점 기억하기
고민 no.2
[ PROBLEM ]
리뷰 작성 섹션은 어찌저찌 submit까지 무사히 되도록 구현해놓았는데, submit 이후 input 창이 비워지지 않는 문제가 발생했다. 그냥 넘어갈 수도 있겠지만, 실제 사용자가 이용하는 상황이라면 실수로라도 동일한 값이 재등록되거나, 리뷰가 등록되었는지 헷갈리게 할 수 있으므로 비우는게 맞겠다는 판단이 들었다. textarea
로 이루어진 부분은 value와 state값을 동기화함으로써 생각보다 쉽게 처리할 수 있었으나 input type='radio'
나 input type='file'
의 경우, 이런저런 방법을 써도 생각대로 되지 않았다.
[ SOLUTION ]
이 문제는 함수형 컴포넌트에서 DOM에 직접 접근할 수 있게 도와주는 useRef
를 사용하여 해결할 수 있었다.
- 새로운 변수에
useRef()
를 선언 - 컨트롤이 필요한 부분에 ref 속성을 부여
- ref의
current
속성을 다양하게 활용하여 원하는 형태로 처리
라디오 버튼의 경우에는 각각의 라디오 버튼을 scoresRef
라는 변수 내 배열의 요소로 저장하고, submit 후 각 버튼을 검사하며 (배열을 돌며) 모든 버튼의 체크 값을 false
로 변경해줌으로써 원하는 형태를 구현할 수 있었다.
input type='file'
은 조금 더 간단했는데, submit이 완료되면 reviewRef
의 값을 빈 string으로 재할당하여 input을 비울 수 있었다.
또한 깨알같이 코드를 간결하게 만들어주었던 tip 중 하나!
resetReviewInputs()
함수를 선언하고, 해당 함수 내에서 reset 부분을 한 번에 컨트롤 할 수 있게 하였다.
import React, { useState, useRef } from 'react';
import { API } from '../../../config';
export default function ReviewInputBox() {
const [reviewImg, setReviewImg] = useState();
const [reviewScore, setReviewScore] = useState();
const [reviewDescription, setReviewDescription] = useState();
const scoresRef = useRef([]);
const reviewRef = useRef();
function resetReviewInputs() {
setReviewImg(null);
setReviewScore(null);
setReviewDescription('');
scoresRef.current.forEach(input => (input.checked = false));
reviewRef.current.value = '';
}
function submitReview(e) {
e.preventDefault();
const formData = new FormData();
formData.append('filename', reviewImg);
formData.append('star_rate', reviewScore);
formData.append('comment', reviewDescription);
formData.append('option_id', 1);
fetch(`${API.reviews}/review`, {
method: 'POST',
headers: {
Authorization: localStorage.getItem('token'),
},
body: formData,
})
.then(res => res.json())
.then(res => {
if (res.message === 'SUCCESS') {
alert('리뷰 등록이 완료되었습니다.');
} else if (res.message === 'INVALID_TOKEN') {
alert('먼저 로그인해주세요');
} else {
alert('모든 리뷰 칸을 작성해주세요.');
}
});
resetReviewInputs();
}
[라디오 버튼]
export default function StarRateInput(props) {
return STAR_RATE_DATA.map((starRate, idx) => (
<React.Fragment key={idx}>
<StarRate
type="radio"
name="starRate"
id={starRate.id}
ref={ref => (props.scoresRef.current[idx] = ref)}
onClick={() => {
props.handleScoreChange(starRate.value);
}}
/>
<StarImg alt="star rate" src={starRate.img} />
</React.Fragment>
));
}
[이미지 파일]
<ImageInput
id="ImageInput"
type="file"
accept="image/jpeg image/png"
onChange={handleImgChange}
ref={reviewRef}
/>
그 외의 소소한 TIP
input type='file'
을 서버로 전달하면 해당 이미지를 서버에서 받아 AWS에 저장하고 업로드 링크를 재저장하는 프로세스로 진행됨. 우리가 그 이미지를 요청할 땐 AWS에 저장된 링크를 받아 화면에 그려주는 것!input type='file'
을 서버로 전달할 때는json
형식이 아닌formData
형식으로 전달해주어야 함- 조건부 랜더링 시
Array.length > 0
을 주로 활용하는 배열과 달리, 길이를 판단할 수 없는 객체를 조건부 랜더링하기 위해서Object.keys
를 활용하면 쉽다.
Object.keys
는 객체의 키값을 배열로 저장해주는 메소드!
Author And Source
이 문제에 관하여(React | '프립' 모티브 프로젝트 코드공유), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@eliz/React-프립-모티브-프로젝트-코드공유저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)