빅 데이터 목록 렌 더 링 시리즈 (3) 가 변 사이즈

5670 단어 variableslist
지난 절 에 우 리 는 고정 사이즈 의 가상 목록 을 실현 했다. 이 절 에서 우 리 는 난이 도 를 높이 고 고정 사이즈 가 아 닌 가상 목록 을 실현 했다.
수요
크기 가 고정 되 지 않 은 가상 목록 을 만 듭 니 다.사용 방식 은 다음 과 같 습 니 다.
const rowHeights = new Array(1000)
  .fill(true)
  .map(() => 25 + Math.round(Math.random() * 50));
 
const getItemSize = index => rowHeights[index];
 
const Row = ({ index, style }) => (
  
Row {index}
); const Example = () => ( {Row} );

분석 하 다.
사이즈 크기 가 고정 되 지 않 은 것 과 지난 절의 고정 사이즈 가 어떤 차이 가 있 는 지 생각해 보 세 요.고려 해 보면 우 리 는 전체 절차 의 논리 가 똑 같다 는 것 을 알 게 되 었 다. 모든 요소 의 포 지 셔 닝 을 계산 할 때 사이즈 가 다 르 기 때문에 계산 방식 이 다르다 는 것 을 제외 하고.사이즈 가 일치 하지 않 으 면 우 리 는 모든 요소 의 실제 크기 와 위 치 를 누적 적 으로 계산 해 야 한다.쉽게 말 하면 고정 사 이 즈 를 바탕 으로 보조 계산 함 수 를 업데이트 하 는 것 이다.
실현 원리
  • 고정 사이즈 가 아니 기 때문에 색인 0 부터 모든 데이터 에 대응 하 는 offset 과 size 를 계산 해 야 합 니 다. 이렇게 순 서 는 뒤로 계 산 된 것 과 계산 되 지 않 은 것 으로 나 뉘 어 집 니 다.
  • 계 산 된 대상 캐 시 를 사용 하고 나중에 사용 할 때 캐 시 에서 직접 사용 합 니 다.
  • onScroll 스크롤 이벤트 에 서 는 offset 에 따라 해당 하 는 startIndex 의 offset 을 찾 아야 합 니 다. 여기에 두 가지 상황 이 있 습 니 다. 캐 시 되 어 있 습 니 다. 캐 시 구간 에서 찾 으 면 됩 니 다. 이분 검색 법 으로 검색 효율 을 높 일 수 있 습 니 다.캐 시 되 지 않 았 다 면 지수 검색 법 으로 검색 범위 구간 을 좁 힌 다음 2 분 검색 법 으로 검색 할 수 있 습 니 다
  • 이루어지다
    지난 절 에 말 한 것 을 근절 하려 면 우 리 는 다음 과 같은 몇 가지 보조 함 수 를 실현 해 야 한다.
    //            
    getItemOffset(index) {}
    
    //              
    getItemSize(index) {}
    
    //        
    getEstimatedTotalSize() {}
    
    //        offset             startIndex
    getStartIndexForOffset(offset) {}
    
    //         startIndex             endIndex
    getStopIndexForStartIndex() {}

    측정 한 데 이 터 를 캐 시 하기 위해 서 인 스 턴 스 에 속성 을 마 운 트 합 니 다:
    instance.instanceProps = {
          itemMetadataMap: {}, //     
          estimatedItemSize: estimatedItemSize, //         size
          lastMeasuredIndex: -1, //           
    };

    그 다음 에 우 리 는 모든 item 에 대응 하 는 정 보 를 얻 기 위해 보조 적 인 방법 을 추가 합 니 다. 캐 시 캐 시 가 있 으 면 캐 시 를 받 고 없 으 면 계산 하여 저장 합 니 다. 다음 과 같 습 니 다.
    getItemMetadata(props, index, instanceProps) {
      const { itemSize } = props;
      const { itemMetadataMap, lastMeasuredIndex } = instanceProps;
      // itemMetadataMap       size     
      if (index > lastMeasuredIndex) {
        let offset = 0; //   ,       0
    
        //      offset,  for      
        if (lastMeasuredIndex >= 0) {
          const itemMetadata = itemMetadataMap[lastMeasuredIndex];
          offset = itemMetadata.offset + itemMetadata.size;
        }
        for (let i = lastMeasuredIndex + 1; i <= index; i++) {
          let size = itemSize(i);
          itemMetadataMap[i] = {
            offset,
            size,
          };
          offset += size;
        }
        instanceProps.lastMeasuredIndex = index;
      }
      return itemMetadataMap[index];
    }

    그리고 상술 한 보조 함 수 를 하나씩 실현 한다.
    getItemOffset && getItemSize
    //            
    getItemOffset: (index) => getItemMetadata(props, index, instanceProps).offset
    
    //              
    getItemSize: (index) =>
        instanceProps.itemMetadataMap[index].size

    getEstimatedTotalSize
    //              +         
    const getEstimatedTotalSize = (
      { itemCount },
      { itemMetadataMap, estimatedItemSize, lastMeasuredIndex }
    ) => {
      let totalSizeOfMeasuredItems = 0;
    
      if (lastMeasuredIndex >= 0) {
        const itemMetadata = itemMetadataMap[lastMeasuredIndex];
        totalSizeOfMeasuredItems = itemMetadata.offset + itemMetadata.size;
      }
    
      const numUnmeasuredItems = itemCount - lastMeasuredIndex - 1;
      const totalSizeOfUnmeasuredItems = numUnmeasuredItems * estimatedItemSize;
    
      return totalSizeOfMeasuredItems + totalSizeOfUnmeasuredItems;
    };
    

    getStartIndexForOffset
    getStartIndexForOffset: (props, offset, instanceProps) =>
        findNearestItem(props, instanceProps, offset)

    검색 알고리즘 에 대한 설명 이 필요 합 니 다.
    const findNearestItem = (props, instanceProps, offset) => {
      const { itemMetadataMap, lastMeasuredIndex } = instanceProps;
      //                offset  
      const lastMeasuredItemOffset =
        lastMeasuredIndex > 0 ? itemMetadataMap[lastMeasuredIndex].offset : 0;
    
      if (lastMeasuredItemOffset >= offset) {
        //                ,          
        return findNearestItemBinarySearch(
          props,
          instanceProps,
          lastMeasuredIndex,
          0,
          offset
        );
      } else {
        //          ,            
        //                    
        return findNearestItemExponentialSearch(
          props,
          instanceProps,
          Math.max(0, lastMeasuredIndex),
          offset
        );
      }
    };
    
    //          ,      。
    const findNearestItemBinarySearch = (
      props,
      instanceProps,
      high,
      low,
      offset
    ) => {
      while (low <= high) {
        const middle = low + Math.floor((high - low) / 2);
        const currentOffset = getItemMetadata(props, middle, instanceProps).offset;
    
        if (currentOffset === offset) {
          return middle;
        } else if (currentOffset < offset) {
          low = middle + 1;
        } else if (currentOffset > offset) {
          high = middle - 1;
        }
      }
    
      if (low > 0) {
        return low - 1;
      } else {
        return 0;
      }
    };
    
    //        ,      。
    const findNearestItemExponentialSearch = (
      props,
      instanceProps,
      index,
      offset
    ) => {
      const { itemCount } = props;
      let interval = 1;
    
      while (
        index < itemCount &&
        getItemMetadata(props, index, instanceProps).offset < offset
      ) {
        index += interval;
        interval *= 2;
      }
    
      return findNearestItemBinarySearch(
        props,
        instanceProps,
        Math.min(index, itemCount - 1),
        Math.floor(index / 2),
        offset
      );
    };

    좋은 웹페이지 즐겨찾기