3. 리액트 성능 최적화에 관하여..
가상돔부분과 실제돔 부분에서 성능을 최적화 하는 방법에 관하여
리액트를 하면서 map 함수를 이용할때가 많았는데, 그때마다 key속성을 이용하여 고유값을 지정해주지 않으면 콘솔에 경고창이 뜨곤했다. 오류가 아니라서 실행이 안되지는 않았지만 주변사람들한테 물어보면 성능상의 이점을 위해서라고 했는데 그 이유는 명확히 알지 못했고 그러려니하고 넘어갔다. 오늘은 왜 리액트에서 key값을 입력하라고하는지, 그리고 성능상의 이점이 뭔지 알아보려고한다.
위의 gif를 보면 사과,바나나에서 사과,바나나,파인애플로 변경될떄 마지막 파인애플 p태그만 리액트에서 추가해주고 제거해주고있다. 이것이 가상돔 비교를 통하여 변경된 부분만 실제돔에 추가해주고 변경해주는 부분인것이다. 여기서 중요한것은, ***리액트는 순서정보를 기억한다.*** 앞서 useState같은경우에도 리액트에서는 순서정보를 기억하기때문에 상태값을 if문이나 for문에 넣어 때마다 존재하거나 수가 늘어나게하면 리액트에서 오류가 발생할 가능성이 높아진다. 위의 경우 사과 바나나 순서는 같지만 파인애플이 마지막에 추가되었다 이런경우에는 당연히 사과 바나나는 추가,변경이 필요없고 끝부분에 파인애플만 추가하거나 제거해주면 간단하다. 그렇다면 사과 바나나 사이에 파인애플이 들어간다면 리액트에서는 어떻게 할까?
옆에 개발자도구를 보면 처음과는 달리 파인애플을 중간에 넣었더니 바나나 또한 영향을 받고있다. 사과와 바나나 사이에 파인애플만 추가 제거 되는것이아니라 사과를 제외한 바나나 파인애플 모두 영향을 받고있다. 리액트는 바나나는 변경되지 않았다는 것을 알지못한다. 바나나는 변경되지않고 중간에 파인애플이 들어왔다는것을 알기위해서는 비교연산이 증가하기때문이다. 이경우에는 복잡하지 않기때문에 별 영향이 없을것같지만 요소가 많아지거나 복잡해지면 연산량이 그만큼 배로 증가하기때문.. 즉 리액트는 효율적으로 연산하기 위해서 순서정보를 이용하는데 위의 경우에는 사과는 변경이 없고 바나나-> 파인애플로 변경이되었기때문에 바나나를 파인애플로 그리고 바나나를 추가한다. 그렇다면 어떻게하면 바나나는 변경하지않고 파인애플만 중간에 추가할 수 있을까.. 이럴때 key속성을 이용하면된다.
이렇게 해주면 사과 바나나 요소는 영향을 받지않고 파인애플만 중간에 추가된다. 이렇게 key속성을 입력해주면 리액트는 같은 key를 갖는 요소끼리만 비교한다.(즉, 바나나 요소가 변경되지 않았다는 것을 이제 리액트도 알고있다.)
key속성값을 입력할때는 주의해야 할 것이 있다. 순서정보를 입력할때는 배열의 끝에서만 원소를 추가하거나 삭제할때 좋을것이다 만약에 중간에 값을 넣어버리면 순서들이 다 뒤엉키기때문에 랜더시 비효율적이기때문이다. 대부분의 경우 고유 아이디 값을 입력해주는게 좋다.
위와 같은 경우에는 key={index}
보다는 key={item}
이 더 좋다.
기타: key를 이용해서 컴포넌트를 의도적으로 언마운트 시키는 경우
<UserDetail key={user.id} user={user} />
유저가 변경됬을때 유저의 상태값을 초기화 시키고싶은경우 key값에 저렇게 user.id를 입력해주면 유저가 변경되면 새로운 컴포넌트를 만들어 그안에 상태값을 초기화 시켜줄수 있다.