ReactJS의 평등 - The ShallowEqual

14056 단어 reactjavascript
React는 프론트엔드 애플리케이션을 위한 매우 강력한 라이브러리이지만 JavaScript 기반을 감안할 때 유형 간의 평등의 뉘앙스를 이해하는 것이 중요합니다. 나는 뉘앙스가 이해되지 않는 많은 코드를 보았고, 여기에는 "지연"앱에서 실수로 마이크로 서비스를 DDOS하는 것에 이르기까지 다양한 문제가 있었습니다. 😕

소개



React Rendering에 대한 간략한 요약.

3가지 조건 중 하나가 충족되면 구성 요소가 다시 렌더링됩니다.
  • props 변화.
  • state 변경됩니다.
  • 부모가 다시 렌더링합니다.

  • 이 게시물에서는 포인트 1, "그것의 props 변화"에 초점을 맞출 것입니다.

    얕은평등



    우리가 어딘가에 도달하기 전에 "변화"가 무엇을 의미하는지 물어야 합니다.

    React 자체의 source code을 보고 봅시다!
    shallowEqual
    /**
     * Performs equality by iterating through keys on an object and returning false
     * when any key has values which are not strictly equal between the arguments.
     * Returns true when the values of all keys are strictly equal.
     */
    function shallowEqual(objA: mixed, objB: mixed): boolean {
      if (Object.is(objA, objB)) {
        return true;
      }
      if (
        typeof objA !== 'object' ||
        objA === null ||
        typeof objB !== 'object' ||
        objB === null
      ) {
        return false;
      }
      const keysA = Object.keys(objA);
      const keysB = Object.keys(objB);
      if (keysA.length !== keysB.length) {
        return false;
      }
      for (let i = 0; i < keysA.length; i++) {
        if (
          !hasOwnProperty.call(objB, keysA[i]) ||
          !Object.is(objA[keysA[i]], objB[keysA[i]])
        ) {
          return false;
        }
      }
      return true;
    }
    


    이 코드는 React의 Reconciler가 props의 변경 사항을 기반으로 구성 요소를 업데이트해야 하는지 여부를 결정할 때 실행됩니다(같은 스타일의 검사는 React에서도 다른 곳에서 동등성을 위해 사용되지만 여기서는 props에 초점을 맞출 것입니다). 첫 번째 인수objA는 이전 소품이고 두 번째 인수objB는 다음 소품입니다.

    Object.is()



    여기서 이해해야 할 핵심은 for 루프 검사의 다음 줄입니다.

    !Object.is(objA[keysA[i]], objB[keysA[i]])
    


    React가 하는 것은 특정 prop이 Object.is 으로 다음 prop과 동일한지 확인하는 것입니다.
    Object.is 평등에 대한 엄격한 검사입니다. 두 가지가 동일합니다(동일함과 의미상 다름).
    Object.is 는 기본 유형 undefinednull 에서 예상한 대로 정확히 작동합니다.

    Object.is(1, 1) // true
    Object.is('Hello World', 'Hello World') // true
    Object.is(true, true) // true
    Object.is(undefined, undefined) // true
    Object.is(null, null) // true
    


    많은 사람들이 빠지는 함정은 참조 유형(객체, 배열, 함수)에 있습니다. Object.is는 이들의 메모리 참조를 확인합니다. 동일한 경우에만 true 반환합니다.

    Object.is(['a'], ['a']) // false
    Object.is({ a: 1 }, { a: 1 }) // false
    Object.is(() => {}, () => {}) // false
    


    각 인수는 동일한 값을 가진 개체에 대한 새로운 참조이므로 false가 결과입니다. 우리가 갔다면 :

    const array = ['a'];
    Object.is(array, array); // true
    


    이번에는 참조가 메모리의 동일한 배열에 대한 것이므로 Object.istrue 를 반환합니다.

    컴포넌트 렌더링



    그러나 이것이 React 구성 요소에 대해 무엇을 의미합니까?

    예를 들어보겠습니다(유형이 지정된 props가 명시적임 😁):

    interface AppleProps {
      isBrusied: boolean;
      info: {
        type: string;
        color: 'red' | 'green';
      }
    }
    const Apple = ({
      isBruised,
      info
    }) => (
      <div>{`Imagine I'm an apple! ${isBruised, info.type, info.color}`}</div>
    );
    


    이제 Apple 🍎가 있습니다.

    다음과 같이 처음 렌더링되었다고 가정해 보겠습니다.

    <Apple isBrusied={false} info={{ type: 'jazz', color: 'red' }} />
    


    그리고 부모의 모든 후속 렌더링에는 똑같은 소품이 있는 사과, 상처가 나지 않은 빨간색 재즈 사과 😋가 있습니다.
    props 변경만 고려하면 Apple이 다시 렌더링합니까?

    불행히도 우리에게 사과의 props는 동일하지만 shallowEqual 에 따르면 동일하지 않습니다. info가 물건이기 때문에 범인이다. shallowEqual는 서로 다른 메모리 주소를 참조하므로 항상 이전info이 다음info과 같지 않음을 반환합니다.

    이것은 Apple가 지속적으로 불필요하게 다시 렌더링된다는 것을 의미합니다.

    잠재적인 솔루션



    이 게시물을 너무 길게 만들지 않기 위해 이 문제를 해결하기 위해 존재하는 useCallbackuseMemo와 같은 후크를 탐구하지 않겠습니다. 후속 조치에서 다룰 수 있습니다. 이 솔루션은 이를 무시합니다.

    기본 유형 대 참조 유형에 대해 우리가 알고 있는 것에서. info를 두 개의 기본 유형으로 분할해 보겠습니다. 우리는 이제 이런 모양의 애플을 갖게 될 것입니다.

    <Apple isBruised={false} type={'jazz'} color={'red'} />
    


    이렇게 하면 세 가지 소품이 모두 동일하게 유지되면 구성 요소가 렌더링되지 않습니다. 이제 더 최적화된 응용 프로그램으로 나아가고 있습니다!

    결론



    React의 동등성 검사는 변경을 결정할 때 엄격한 검사를 사용합니다. 기본 유형은 예상대로 작동하지만 함수, 객체 및 배열과 같은 참조 유형을 사용할 때 주의하지 않으면 애플리케이션에 불필요한 변경이 발생할 수 있음을 기억하는 것이 중요합니다.

    읽어주셔서 감사합니다 🎖! 나는 이 얕은 평등도 적용되는 useCallbackuseMemo와 이러한 후크가 존재하는 이유에 대해 자세히 알아보기 위해 이 게시물을 따르기를 바랍니다.

    좋은 웹페이지 즐겨찾기