빅 데이터 목록 렌 더 링 시리즈 (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}
);
분석 하 다.
사이즈 크기 가 고정 되 지 않 은 것 과 지난 절의 고정 사이즈 가 어떤 차이 가 있 는 지 생각해 보 세 요.고려 해 보면 우 리 는 전체 절차 의 논리 가 똑 같다 는 것 을 알 게 되 었 다. 모든 요소 의 포 지 셔 닝 을 계산 할 때 사이즈 가 다 르 기 때문에 계산 방식 이 다르다 는 것 을 제외 하고.사이즈 가 일치 하지 않 으 면 우 리 는 모든 요소 의 실제 크기 와 위 치 를 누적 적 으로 계산 해 야 한다.쉽게 말 하면 고정 사 이 즈 를 바탕 으로 보조 계산 함 수 를 업데이트 하 는 것 이다.
실현 원리
지난 절 에 말 한 것 을 근절 하려 면 우 리 는 다음 과 같은 몇 가지 보조 함 수 를 실현 해 야 한다.
//
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
);
};