create 구현 : shouldComponentUpdate

SPANKEEE·2023년 3월 15일
0

리액트-시작

목록 보기
25/30

원본 유지하기 : concat 활용

이전에 사용한 함수 push()concat()을 확인해보자.

// push()
var a = [1,2];
a.push(3);
console.log(a);
---
(3) "1, 2, 3"

위 console 창을 확인하면 a 배열[1, 2, 3] 이다.

이 코드를 push() 를 사용하지 않고 concat() 을 사용한다면 원본을 바꾸지 않기 때문에 a 의 값은 여전히 [1, 2] 을 유지한다.

// concat()
var a = [1,2];
var b = a.concat(3);
console.log(a,b);
---
(2) "1, 2",
(3) "1, 2, 3"

concat리턴 값을 b 로 담고

ab 를 비교하면

concat() 은 원본을 바꾸지 않고 새로 만든 복제본이라는 것 을 알 수 있다.

  • setState() 에 어떤 값을 수정할 때
  • 원본 을 수정하지 말고 원본복제본 을 수정해서
  • 복제본setState()의 값 으로 하는 것이 이번 시간의 핵심이다.

현재 지금 만지작 거리고 있는 애플리케이션은 조금 불합리한 면을 가지고 있다.

글 목록인 <Navi> 컴포넌트가 화면에 표시되기 위해서 contents 가 담고 있는 배열들이 필요하다.

이 배열의 내용이 바뀌었다면 <Navi> 컴포넌트와 상관없는 일이 진행되고 있는데도

<Navi> 컴포넌트의 render 는 호출이 되는 것은 매우 불합리한 상황일 수 있다.


shouldComponentUpdate( ... , ... )

페이스북에서는 성능을 향상시키고 싶을 때
어떤 컴포넌트의 render 함수 가 실행될지 실행되지 않을지를 개발자가 결정할 수 있도록 shouldComponentUpdate 라는 특수한 약속의 함수를 제공한다.

shouldComponentUpdate(){
  colsole.log("===>Navi render shouldComponentUpdate!!!");
  return true;
}

위 코드를 추가해서 어떤 상태가 바뀔 때마다 shouldComponentUpdate 함수가 호출된 다음에 render 함수가 호출되는 것을 확인할 수 있다.

이전에는 Navi 컴포넌트의 state 값이 바뀌면 그 자식 컴포넌트들은 모두 render가 호출되었다.

shouldComponentUpdate의 리턴 값을 무조건 flase 로 변경하면
shouldComponentUpdate는 호출되지만 render 함수는 호출되지 않는다.

심지어 글을 작성해도 rneder() 함수가 호출되지 않았기 때문에 글목록은 반영되지 않는다.

shouldComponentUpdate 함수는 "newProps" , "newState" 두 개의 매개 변수를 갖도록 약속되어 있다.

이름처럼 Navi 컴퍼넌트의 props(속성) 가 바뀌었을 때 그 바뀐 값, state 가 바뀌었을 때 그 바뀐 state 값이 들어온다.

shouldComponentUpdate(){
  console.log('===> Navi render shouldComponentUpadate!!!'
	,newProps.data		// 변경 후
    ,this.props.data 	// 변경 전
  );
  debugger; // 디버거로 확인해보기
  return true;
}

변경 된 값을 확인하기 위해 shouldComponentUpdate 함수를 위 코드와 같이 변경한다.

  • 결과

글 목록을 클릭하면 newProps.datathis.props.data 는 동일한 것을 확인할 수 있다.


하지만 글을 작성해보면 newProps.data 는 원소가 4개인 배열이고, this.props.data 는 원소가 3개인 데이터다.

즉, 첫 번째 인자를 통해서 바뀐 값을 알 수 있고 두번째 인자를 통해서 현재 값을 알 수 있다.

  • 정리
    1. render 이전에 shouldComponentUpdate()가 실행된다.
    2. shouldComponentUpdate의 리턴값이 true면 render()가 호출되고 false면 render가 호출되지 않도록 약속되어 있다.
    3. shouldComponentUpdate는 새롭게 바뀐 값과 이전 값에 접근할 수 있다.

이것을 종합해 Navi 컴포넌트로 들어오는 data 라는 prorps 의 값이 바뀌었을 때

this.props.data 값과 newProps.data 의 값이 서로 같다면 바뀐게 없으므로 false,
그렇지 않으면 true를 리턴하도록 변경한다.


ShouldComponentUpdate(){
  console.log("===>Navi render shouldComponentUpdate!!!"
    , newProps.data
    , this.props.data
  );
  if(this.props.data === newProps.data){
    console.log("render : false");
    return false;
  }
  console.log("render : true");
  return true;
}
  • 기존 <Navi>영역에 있는 컨텐츠 <a> 링크를 클릭하면
    - Alpha 링크 클릭

    render : false

실행해보면 Navi 에 있는 목록들을 클릭할 때 render 함수는 호출되지 않는다.

하지만 글을 작성할 때는 이전 값과 바뀐 값이 서로 다르기 때문에,
리턴값은 true 가 되고 render 함수가 호출된다.


concat() 을 활용해 원본 데이터 유지

만약 글 작성 코드를 concat() 이 아닌 push() 방식으로 구현을 했다면 기존의 this.state.contents의 원본을 바꾸게 된다.

  • push() --> CreateArtionSubmit 이벤트를 push()로 작업할 경우
    ... if(mode === "create")
    <CreateArti.js> onSubmit() 이벤트를 통해 속성에게 새로운값 전달
    콘텐츠 id 값 + 1
    [원본값].push([새로운값])
    this.setState({...})
    render : false

[원본값]shouldComponentUpdate 가 체크하기 전에
이미 [원본값]수정 된 상태이므로, 원본과 비교할 새로운 값이 같다고 인식할 수 밖에 없다.
shouldComponentUpdate 입장 :
원본 값과 새로운 값이 완전히 일치하니까 render 이밴트를 실행하지 말아야지.

  • 즉 비교할 원본대상이 없다.
  • concat() --> CreateArtionSubmit 이벤트를 concat()로 작업할 경우
    ... if(mode === "create")
    <CreateArti.js> onSubmit() 이벤트를 통해 속성에게 새로운값 전달
    // 임시 변수 저장소에 concate활용
    var _contents = this.staet.contents.concat({객체에 새로운 값 주입})
    this.setState({...})
    render : true

_contents 라고 하는 임시 변수에 새로운 값을 넣고,
this.set.Staete({contents : _contents}) 가 실행하면서 steat가 바뀌고
App.js > Navi컴포넌트 props 영역은 :
data={this.state.contents} 로 인해 새로운 데이터가 주입되고
Navi.js > shouldComponentUpdate 이밴트 실행
render : true

concat()을 활용하면 원본값과 새로운 값을 비교할 수 있다.

위와같이 새로운 데이터는 임시 데이터에 저장하고 원본에는 영향을 주지 않았기 때문에

shouldComponentUpdate함수가 데이터를 비교하고 두 값이 같지 않기 때문에

render : true 를 출력하고 해당 컴포넌트를 새롭게 렌더링 하게 된다.

profile
해야되요

0개의 댓글