GDSC 1차 팀프로젝트였던 투표 SNS, Boat-Vote.
배포까지 완료되었지만 해결하지 못했던 문제가 몇 가지 있어 차례차례 해결해보려 한다.
먼저, input 비동기 문제이다.
문제 상황
위 화면은 투표 게시글 작성 팝업에서 투표 항목을 4개 모두 작성한 화면이다.
이 상황에서 세번째 투표 항목을 지울 경우 1, 2, 3, 4에서 1, 2, 4가 되어야 마땅하지만, 1, 2, 3으로 표시되는 문제가 발생하였다.
그와중에 state는 1, 2, 4로 정상적으로 들어가있어 게시글 등록 시에는 1, 2, 4로 정상적으로 나왔다.
즉, state가 변해도 input의 값이 갱신되지 않는 문제가 발생하였다.
원인 파악
원인을 파악하기 위해 3번째 input box의 디자인만 변경한 채로 3번째 input을 삭제해보았다.
기대한 바로는 state가 바뀌면서 리렌더링 되면서 3번째 input 박스가 사라지고 4번째 input box가 올라오는 것이었으나
이와 달리 3번째 input box가 그대로 남아있는 모습을 볼 수 있다.
리액트는 렌더링 시 Cost를 최소화하기 위해 모든 컴포넌트를 렌더링하지 않고, 변경된 부분만 렌더링한다.
바로 이런 특징에서 문제가 발생한 것이다.
{votes.map((vote, index) => (
<div key={index}>
<input
className={index > 1 ? "add-vote-input-box" : "vote-input-box"}
onChange={(e) => changeVoteInput(vote.id, e)}
required
/>
</div>
)}
투표 목록을 표시하는 상태 votes는 { id, content }의 객체 배열이다.
문제는 input의 값은 votes와 관련된 값을 사용하지 않아 input 태그 자체는 votes라는 상태와 분리되어 있었다.
삭제 버튼을 누를 경우 votes의 길이가 4개에서 3개로 바뀌어 input이 3개만 렌더링되나
input box 내부의 값은 state에 묶여있지 않아 변경되지 않은 것이다.
즉, React는 votes의 길이가 바뀜에 따라 input이 렌더링 되는 횟수는 바꾸었으나,
input box 자체는 상태와 엮여있지 않기에 상위 3개의 input box를 변경하지 않고 그대로 둔 것이다.
해결
{votes.map((vote, index) => (
<div key={index}>
<input
className={index > 1 ? "add-vote-input-box" : "vote-input-box"}
value={vote.content}
id={vote.id}
onChange={(e) => changeVoteInput(e)}
required
/>
</div>
)}
input value 값을 통하여 투표 항목을 input value의 값으로 설정해주었다.
즉, input 내부의 값을 votes라는 상태에 함께 엮어준 것이다.
이를 통해 votes의 상태가 바뀌면 input 내부 값 역시 변경하도록 만들어 문제를 해결할 수 있었다.
Github