본문 바로가기
프로젝트

[React] 메모리에 있는 값과 화면에 보여지는 값이 상이한 문제

by 1two13 2023. 3. 8.
728x90
반응형

문제 상황


아래 사진에서 삭제 버튼을 클릭했을 때 메모리에 있는 skillList(redux로 관리하고 있는 배열로, 객체들을 요소로 가지고 있다.)의 값은 변경되지만, 실제 화면에 보여지는 값은 변경되지 않는 문제점이 있었다.

문제 상황

 

 

 

 

시도한 해결방법과 문제점


skillList.map을 실행할 때 주는 key의 값을 index(숫자)가 아닌 랜덤한 값을 주는 방법이였다.

 

이 방법을 시도하게 된 이유는 스킬 추가 버튼을 클릭했을 때 콘솔창에 오류가 발생하는데 key prop이 문제라는 내용의 오류 문구였고, 이를 해결하면 문제 상황이 해결될 줄 알았다. 지금 생각해보면 그 오류는 그 오류고,(사실 오류도 아니였고 warning이였다😂) 값이 변경되지 않는 문제는 다른 문제였을텐데 아무튼 여기에 꽃혀서 빙빙 돌아갔다..

 

결론적으로 랜덤한 값을 key로 줄 수는 없기 때문에 index 값을 key로 주었다. 공식문서에 따르면 key는 반드시 변하지 않고, 예상 가능하며, 유일해야한다고 한다. 변하는 key를 사용하게 되면 많은 컴포넌트 인스턴스와 DOM 노드를 불필요하게 재생성하게 되어 성능이 나빠지거나 자식 컴포넌트의 state가 유실될 수 있기 때문이다.

 

하지만 index 값을 key로 사용하게 되면 상태가 뒤죽박죽 된다. 공식문서에도 나와있듯이 컴포넌트 인스턴스는 key를 기반으로 갱신되고 재사용되기 때문에 인덱스를 key로 사용하면, 항목의 순서가 바뀌었을 때 key 또한 바뀌기 때문이다. 

728x90
반응형

 

다시말해, key가 변경되면

1. key가 다르니 html 코드 자체를 삭제 후 새로 생성

2. html 코드 자체가 재생성

 

그래서 2번 스킬을 삭제했음에도 불구하고, html 코드 자체가 재성되어 1, 2, 3, 4 번째의 스킬이 노출되게 되는 것이다.

 

 

 

최종 해결방법


하지만, 내가 원했던 결과화면은 2번 스킬을 삭제했을 때, 1, 3, 4, 5가 보여야 한다. index를 key로 사용하면서도 뒤죽박죽인 상태를 피할 수 있는 방법이 있다.

 

input에 value 옵션을 주면 된다. input에 value 옵션을 작성해주면 화면에 반영이 되기 때문이다.(이 점을 간과했다ㅠ 아차차)

 

마찬가지로 2번 째 스킬을 삭제해보면 정상적으로 스킬이 삭제되어 2번 째 스킬 자리가 3번 째 스킬의 값으로 변경된 것을 확인할 수 있다. 문제를 해결하느라 빙빙 돌았지만 너무 간단하게 해결했다. 핵심은 html 코드는 화면에 노출되는 값이고 실제 메모리랑 값이 별개라는 점이다. 

 

다시말해,

1. key는 index 값으로 사용

2. react 입장에서 스킬이 5개에서 4개로 줄었으니 마지막 html만 삭제 (1 ~ 4번 스킬의 html은 냅두기)

3. 화면에 노출되는 html은 변동되지 않음

4. 3번 문제를 해결하기 위해 Input의 value를 이용해서 html 갱신

 

위와 같은 동작이 가능한 이유는 react는 virtual DOM이라는 특징을 가지고 있기 때문이다.

따로 정리해둔 글이 있으니깐 참고 하면 좋을 것 같다! ⬇️⬇️⬇️

 

React Virtual DOM이란?

DOM이란? 브라우저는 화면을 그리기 위해서 DOM(Document Object Model)이라는 개념을 사용한다. DOM은 HTML 파일 내용을 토대로 만들어지는데, JavaScript와 같은 언어로 수정할 수 있도록 만들어진 웹 페이

1two13.tistory.com

 

 

 

최종 코드 및 결과 화면


// src/components/makeCharacter/Skill.tsx

return (
  <>
    {skillList.map((skill, index: number) => (
      <div key={index} className="flex max-h-[72%] pl-[1%]">
        <input
          value={skill.title}
          onChange={(e) => onChangeTitle(e, index)}
          placeholder="스킬"
          className="w-[40%] mr-[2%] text-center bg-deepGray"
        />
        // ...
        <input
          value={skill.description}
          onChange={(e) => onChangeDescription(e, index)}
          placeholder="자세한 설명"
          className="w-[100%] mb-[2%] pl-[1%] bg-deepGray"
        />
      </div>
    ))}
  </>
);

2번 째 스킬을 삭제했을 때 정상적으로 스킬이 삭제되어 2번 째 스킬 자리가 3번 째 스킬의 값으로 변경되었다.

 

 

 

참고자료


 

 

 


질문이나 잘못된 점은 댓글로 남겨주세요 :)💖

728x90
반응형

댓글