React 9일차

제어되지 않는 컴포넌트

제어되지 않는 컴포넌트는 진리의 원천(유일한 진리의 원천x)을 DOM에 두기 때문에,
React를 사용한 코드와 사용하지 않은 코드를 통합하는 작업을 좀 더 쉽게 만들어줄 수 있습니다.

기본값 지정하기

  • value 속성을 이용하면, 제어되는 컴포넌트가 됨
  • defaultValue를 이용하면, 기본값을 주면서도 사용자가 편집 가능 (기본값도 지울 수 있음)
    제어되지 않는 컴포넌트 만드는 법
  • <input type="checkbox"><input type="radio"> 엘리먼트는
    'defaultChecked' 어트리뷰트(제어되지 않는 컴포넌트이면서도 체크된 상태로 기본값 주고 싶을 때)
  • <select><textarea>는 ‘defaultValue’ 어트리뷰트를 지원합니다.

The file input Tag

  • cf) input type을 file로 주고, 속성을 multiple 주면 파일 여러 개 업로드 가능

입력받은 파일과 상호작용하기 위해서는 File API를 사용해야만 합니다.
아래 예제는 submit 이벤트 핸들러 내에서 파일에 접근하기 위해 DOM node를 가리키는 ref를 생성하는 방법을 보여줍니다:

  • 바로 아래 예제는 예전 ref 사용법임

  • cf) 비관적 업데이트 vs 낙관적 업데이트
    비관적 업데이트 - 사용자가 좀 기다려야함.
    낙관적 업데이트 - 서버와 통신에 실패했을 때 처리가 어려움

성능 최적화

  • 리액트 개발 시 중요한 이슈
  • react는 setState가 일어난 컴포넌트의 모든 자식 컴포넌트를 다시 호출한다.
    –> ( 모든 자식 컴포넌트의 render 메소드를 호출한다.)
    -> 매번 새로 계산해야 한다.
    -> 이 계산을 하는 게 느릴 수 있다.
    props와 state는 둘 다 객체임
    props와 state의 속성이 바뀌지 않았다면 render메소드를 다시 호출할 필요가 x
    render함수는 순수함수(같은 입력 -> 같은 출력)

불변성(PureComponent 실습 코드)
key를 이용해서 상태를 초기화하는 예제


불변성을 유지할 수 있게하는 라이브러리

immutable.js

immutable.js 예시 코드

immer

  • immer가 점점 뜨고 있음. 페이스북도 immer 사용을 권장
  • immer는 내장 객체와 내장 배열을 사용.
  • -> 이 라이브러리를 이용하면, 기존의 메소드를 사용하면서도 불변성을 유지할 수 있다.

비교조정 (Reconciliation) 피하기

  • shouldComponentUpdate 를 재정의하여 이러한 모든 것을 가속할 수 있습니다.
    이 함수의 기본 구현체는 ‘true’를 반환하고 React는 업데이트를 수행합니다.
1
2
3
shouldComponentUpdate(nextProps, nextState) {
return true;
}
  • 일부 상황에서 컴포넌트를 업데이트할 필요가 없는 경우
    shouldComponentUpdate 에서’false’ 를 반환하여
    이 컴포넌트 및 하위에서 호출하는 render()를 포함한 전체 렌더링 프로세스를 스킵할 수 있습니다.

  • PureComponent에 shouldComponent가 내장되어 있는 것임

  • 직접 shouldComponentUpdate를 세밀하게 만져도 된다.

비교조정 (Reconciliation)

  • React는 선언적 API를 제공하기 때문에 갱신이 될 때에 정확히 무엇이 바뀌었는지를 걱정할 필요가 없습니다.

동기

    1. 다른 타입을 가진 두 엘리먼트는 다른 트리를 만들어 낼 것이다.
  • ex) ‘div를 table로 고쳐줘라.’ 라고 하면, 엘리먼트의 타입을 바꾸라고 했으므로
    -> 그 하위 트리는 비교를 수행하지 않고 싹 새로 그린다.
  1. 개발자가 제공한 key prop을 이용해,
    여러 번의 렌더링 속에서도 변경되지 말아야 할 자식 엘리먼트가 무엇인지를 알아낼 수 있을 것이다.
  • -> ‘엘리먼트 타입’이나 ‘key’가 바뀌면 -> 더 이상 비교하지 않고, 새로 그린다.

  • 비교를 할 때는 맨 위 엘리먼트부터 비교한다.

비교 알고리즘 (Diffing Algorithm)

  • 두 트리를 비교할 때 React는 가장 먼저 두 루트 엘리먼트를 비교합니다.
  • 이후의 동작은 루트 엘리먼트들의 타입에 따라 다릅니다.

다른 타입의 엘리먼트인 경우

1
2
3
4
5
6
7
8
9
10
루트 엘리먼트들의 타입이 다르다면, React는 이전 트리를 버리고 트리를 완전히 새로 구축합니다.

트리를 버릴 때, 이전 DOM 노드들은 모두 파괴됩니다.
또한 컴포넌트 인스턴스의 componentWillUnmount() 라이프 사이클 훅이 실행됩니다.
새 트리가 구축될 때, 새 DOM 노드들이 DOM 안에 삽입됩니다.
그에 따라 컴포넌트 인스턴스의 componentWillMount() 훅이 실행되고,
그 다음 componentDidMount() 훅이 실행됩니다.
이전 트리에 연결되어 있던 **모든 state가 유실됩니다.**

루트 엘리먼트 아래에 있는 모든 컴포넌트가 언마운트되고 그 state 또한 파괴됩니다.
  • React의 상태는 화면에 그려질 때만 존재할 수 있다

같은 타입의 DOM 엘리먼트인 경우

1
2
같은 타입의 두 React DOM 엘리먼터를 비교할 때,
React는 양쪽의 속성을 살펴본 뒤 같은 것들은 유지시키고 변경된 속성만을 갱신합니다.
  • -> DOM을 파괴하는 게 X
    두 요소를 비교하여 React는 DOM 노드에서 className만 수정되고있다는 사실을 알게됩니다.
1
하나의 DOM 노드를 처리한 뒤에, React는 뒤이어 해당 노드의 자식들을 재귀적으로 처리합니다
  • -> 하위 요소들에 대해서 똑같은 작업을 수행

같은 타입의 컴포넌트 엘리먼트인 경우

  • 같은 타입의 컴포넌트 엘리먼트인 경우는 prop이 바뀔 뿐 state가 날아가지 않습니다.

  • cf) componentWillReceiveProps()는 요즘은 사용하지 않습니다.

1
2
만약 자식이 키를 갖고 있다면,
React는 그 키를 이용해 원래 트리의 자식과 새 트리의 자식 간이 일치하는 지를 결정할 수 있습니다.
  • 같은 자료면 같은 키를 써야합니다.
  • 같은 자료인데 키를 바꾸면 리액트는 다른 자료라고 인식합니다.
  • 키가 바뀌면 상태가 다 날아갑니다.

  • 내가 상태를 강제로 초기화하고 라이프사이클 훅을 싶을 때도 키를 사용할 수 있습니다.

  • 엘리먼트 타입이나 상태가 바뀌면 상태가 다 날아간다는 걸 기억하세요!