15일차 프레임워크/라이브러리와 레이아웃 구조5

osdsoonhyun·2023년 2월 25일
0

코드캠프

목록 보기
10/22
post-thumbnail
  1. 객체와 배열이 복사가 이상하다? -> Shallow-Copy / Deep-Copy
  2. 스크롤 형태의 페이지네이션을 만들자 -> Infinite-Scroll

얕은 복사 / 깊은 복사

얕은 복사

  • 객체나 배열의 경우 값이 복사되는 것이 아닌 주소 값이 복사가 된다.
  • 따라서 원본 배열을 변경하면 복사본의 값도 바뀌는데 이는 주소값이 같아서 발생하는 것이다.

그렇다면 어떻게 복사를 해야 이런 오류를 막을 수 있을까?

  • 결론부터 말하자면 **객체 복사라는 것은 존재하지 않는다.** **원본 객체와 같은 값을 가진 객체를 새로 만들 수 있을 뿐**이다.

  • 따라서 객체를 복사한다고 하지만, 아래 코드처럼 child2 객체의 각 값을 꺼내서 child3의 각 key에 할당함으로써 복사한 것과 같은 모습이되는 것이다.

  • 엄밀히 말하면 복사는 아니지만, 이러한 것을 객체 복사라고 한다.

  • 이렇게 객체 복사하면 복사본 값을 변경해도 원본의 값이 변경되지 않고 유지된다.

// child3에 child2 복사
let child3 = {
    name: child2.name,
    age: child2.age,
    school: child2.school
}

child3 // {name: '영희', age: 8, school: '다람쥐초등학교'}

소소한 꿀팁
let child2 = {...}에서 중괄호를 여는 순간 메모리에 주소 저장되는 것이다.
객체가 시작하면 주소가 저장된다고 생각하면 된다.
중괄호를 열고 스프레드 연산자를 통해 값을 넣어주는 것이, 엄밀히 말해 값을 복사하는 것이 아닌 새로운 객체에 새로운 주소에 값을 넣어준 것이다.

객체를 복사할 때 마다 모든 값을 가져오는 것은 번거러운 작업인데 객체에 들어가는 데이터의 양이 많아지면 어떻게 될까?

스프레드 연산자

  • 그 때 사용할 수 있는 것이 스프레드 연산자이다.
  • ...을 통해 해당 객체 내의 모든 값을 개별 요소로 분리한다.
  • 스프레드 연산자를 이용해 객체를 복사하면, 복사본의 값을 변경해도 원본 값이 변경되지 않는다.
let child4 = {
	...child2
}

child4 // {name: '영희', age: 8, school: '다람쥐초등학교'}

객체 안에 객체가 값으로 들어가 있는 중첩 객체의 경우도 스프레드 연산자로 복사가 가능할까?

  • 결론 먼저 말하면, 객체 안에 객체가 값으로 들어가 있는 경우 제대로 복사가 되지 않는다.

  • 객체 안의 객체 또한 주소가 저장이 되기 때문에 중첩된 객체를 수정하면 그값의 원본값이 변한다.

  • hobby는 새로운 중괄호를 열고 profile.hobby를 스프레드 해줘야 한다. 그래야 hobby의 메모리 주소를 복사하는 것이 아닌 개별 요소까지 저장할 수 있다.

  • 스프레드를 통해서 하는 복사를 얕은 복사라고 한다.

+ 중첩객체의 깊은 복사

  • 객체의 특정key값의 value만 바꿔주는 방법을 이용

  • 즉, 중첩 객체의 key,value를 다시 스프레드를 이용해서 복사해 오는 것 입니다.

const me = {
	name : "혜원",
	info : {
		nickname : "개구리",
		mbti : "ENTJ",
		position : "프론트엔드" 
	}
}

const copyMe = {...me,info:{...me.info}}
console.log(copyMe)
//결과 
// copyMe = {
//	name : "혜원",
//  info : {
//	nickname : "개구리",
//	mbti : "ENTJ",
//	position : "프론트엔드"
//	}
// }

//깊은 복사가 됐는지 확인해보기
copyMe.info.nickname = "wonny"

console.log(copyMe.info.nickname) // "wonny"
console.log(me.info.nickname)  // "개구리"

아까와는 다르게 중첩객체를 복사해올 때 한번 더 스프레드를 이용해서 복사해왔습니다.

이렇게 하게되면 중첩객체 내부의 property또한 깊은 복사가 되게 됩니다.

깊은 복사

얕은 복사를 하면 깊이가 어디까지 깊어질지 모르는데 한 번씩 계속해줘야 하면 비효율적이지 않는가

  • 객체를 JSON.stringify()에 넣으면 문자열로 변환해주고 다시JSON.parse()에 넣으면 문자열을 기존과 다른 새로운 객체로 만들어준다.
  • 객체를 문자열로 변환하고 새로운 객체로 만들어준 것이다.
  • 성능이 조금 떨어지기 때문에 빠르게 하기 위해 만든 라이브러리를 사용한다.

lodash

  • lodash.cloneDeep()을 사용하여 깊은 복사를 한다.

  • call by value : 데이터의 값, value를 직접 요청한다

  • call by refernce : 객체를 복사한 경우처럼 데이터의 주소를 요청한다.

배열 복사

  • 객체 복사와 동일하게 배열도 객체와 같은 방식으로 복사가 가능하다.

댓글 수정

  • 위와 같이 myIndex 값이 true로 바뀌면 조건부 렌더링에 의해 수정하기가 아닌 input이 나와야 한다.
  • 위 문제는 call by reference와 관련이 있다.
  • setMyIndex에 값을 넣으면 기존에 있던 값과 비교하여 다르면 해당 state를 change 하고 바뀐 state로 해당 컴포넌트를 리렌더 한다.
  • 위에 38~41번째 줄에서 바꾼 행위는 qqq를 직접적으로 바꾼 것과 같다.
  • qqq만 바꿨지만 실제로는 myIndex 값도 바뀐 것이다. -> 같은 주소를 참조하고 있기 때문
  • 그렇기 때문에 qqq를 바꾼 것이 myIndex 값도 바꿨기 때문에 qqq를 myIndex에 집어넣으면(setMyIndex) 똑같은 둘을 비교하기 때문에 setMyIndex 값이 바뀌질 않고 리렌더 되지 않는다.

배열을 변경하고 setState에 값을 넣어주었을 때 리렌더 되지 않는 문제는 어떻게 해결할까?

  • 객체를 복사할 때에도 복사가 없고 새것을 만들어줘야 한다(새로운 중괄호를 통해 새로운 주소를 만들어준다. 그 이후 스프레드로 할당)
  • 배열도 동일하게 새로운 배열을 만들고 스프레드 해주어야 비로소 qqq와 myIndex가 다른 주소를 갖는 다른 값이다.
  • 그렇게 해줘야 setState로 값을 변경했을 때 qqq와 myIndex가 다른 것을 확인하고 값이 변경되고 리렌더링 된다.

소소한 꿀팁
객체나 배열의 경우 값을 복사나 평소에도 일관적으로 얕은 복사하여 넣어줘야 한다. 프로젝트 규모가 커지면 원본 값이 어떻게 사용되는지 모르기 때문에 프로젝트의 안정성을 위해서 얕은 복사해주는 것이 좋다.

실무에서 사용되는 방법

  • 큰 프로젝트에서는 코드의 가독성과 유지보수가 가장 중요하기 때문에 위와 같이 하는 것을 익혀야 한다.

무한스크롤

페이지네이션은 10개가 보여지고 다음 10개가 보여질 때 전의 10개는 사라졌었으나,
무한스크롤에서는 10개가 보여지고 다음 10개가 보여질 때 이전의 10개가지 총 20개가 보여지는 것이 포인트

들어가기 전 사전 지식

  • 무한스크롤을 통해 앞선 10개와 다음에 올 10개가 보여지기 위해서 어떻게 처리해줘야 할까?

라이브러리 사용하기

  • 위처럼 해야 map을 통해서 한번에 전체 댓글을 보여줄 수 있다.

  • 아래에 댓글들을 가져오고 if문을 통해서 다음 페이지에 올 데이터가 없다면 기존에 데이터만 넘겨준다.

  • variables에는 다음에 받아올 페이지를 넣어준다. (ex. 현재 20개 댓글이 있는 2페이지면 다음엔 3페이지)

  • 스크롤 부분은 라이브러리를 사용하고 라이브러리에서 스크롤이 내려갔을 때 함수를 실행시키는데, 그 때 실행시키는 함수가 fetchMore이다.

0개의 댓글