Я создаю пользовательский компонент карты в React Native, который отображает карты процедурных миров из игры. До сих пор я мог панорамировать / масштабировать, переходить к позиции, отображать маркеры и накладывать сетку. Я столкнулся с проблемой: большие карты имеют слишком много элементов, что замедляет рендеринг, и моя попытка отбраковки заключается в перегрузке потока JS, потому что я добавляю / удаляю элементы, что по какой-то причине очень медленное.
Мой подход к отбраковке - просто запустить setState, когда нужно показать разные элементы. Это работает, но поток JS падает почти до 0 FPS, и очередь setStates помещается в очередь, поэтому очень неприятно наблюдать, как отбраковка делает свое дело долго после того, как вы перестанете панорамировать.
Это мой код для части сетки(MapState управляет картой с помощью Reanimated):
import React, { useState, useEffect } from 'react';
import { View, Text } from 'react-native';
import Animated from 'react-native-reanimated';
import { cellSize, convertToMapPosition } from '../../game/Grid';
import { useMapState } from './MapState';
const { add, multiply } = Animated;
export function GridLayer() {
const mapState = useMapState();
const cellDims = cellSize * mapState.imageScale;
const [state, setState] = useState(() => ({
timer: startCulling(),
showLabels: false,
minX: 0,
maxX: 0,
minY: 0,
maxY: 0,
}));
useEffect(() => {
return () => clearInterval(state.timer);
}, []);
function startCulling() {
let prevState = {} as typeof state;
let inFlight = false;
function buildCullingState() {
const scale = mapState.currentScale;
const minXPos = -mapState.currentX / scale;
const minYPos = -mapState.currentY / scale;
const maxXPos = minXPos + (mapState.viewWidth / scale);
const maxYPos = minYPos + (mapState.viewHeight / scale);
const minX = Math.max(Math.floor(minXPos / cellDims) - 1, 0);
const maxX = Math.max(Math.ceil(maxXPos / cellDims) + 2, 0);
const minY = Math.max(Math.floor(minYPos / cellDims) - 1, 0);
const maxY = Math.max(Math.ceil(maxYPos / cellDims) + 2, 0);
const cellScreenSize = cellDims * scale;
const showLabels = cellScreenSize >= 80;
return { ...state, showLabels, minX, maxX, minY, maxY };
}
function doCulling() {
if (inFlight) {
return;
}
let newState = buildCullingState();
if (newState.showLabels != prevState.showLabels ||
newState.minX != prevState.minX ||
newState.maxX != prevState.maxX ||
newState.minY != prevState.minY ||
newState.maxY != prevState.maxY
) {
inFlight = true;
setState(() => {
inFlight = false;
return buildCullingState();
});
}
prevState = newState;
}
return setInterval(doCulling, 15);
}
const cellCount = Math.floor((mapState.imageWidth + cellDims - 1) / cellDims);
const cellOffsets = [];
for (let i = 0; i < cellCount; i++) {
cellOffsets.push(i * cellDims);
}
const cellOffsetsW = cellOffsets.slice(state.minX, state.maxX);
const cellOffsetsH = cellOffsets.slice(state.minY, state.maxY);
const posWidth = 40;
const posHeight = 25;
const posAdjustX = multiply(posWidth, add(-1, mapState.scaleInv), 0.5);
const posAdjustY = multiply(posHeight, add(-1, mapState.scaleInv), 0.5);
return (
<View style={{ position: 'absolute', width: 8192, height: 8192 }}>
{cellOffsetsW.map(x =>
<Animated.View
key={`X-${x}`}
style={{
position: 'absolute',
left: x,
top: 0,
width: mapState.scaleInv,
height: mapState.mapHeight,
backgroundColor: '#0007',
}} />
)}
{cellOffsetsH.map(y =>
<Animated.View
key={`Y-${y}`}
style={{
position: 'absolute',
left: 0,
top: y,
width: mapState.mapWidth,
height: mapState.scaleInv,
backgroundColor: '#0007',
}} />
)}
{state.showLabels && cellOffsetsW.flatMap(x => cellOffsetsH.map(y =>
<Animated.View
key={`L-${x}-${y}`}
style={{
position: 'absolute',
left: x,
top: y,
width: posWidth,
height: posHeight,
margin: 4,
transform: [
{ translateX: posAdjustX },
{ translateY: posAdjustY },
{ scale: mapState.scaleInv },
],
}}>
<Text style={{ color: '#000a' }}>
{convertToMapPosition(x / mapState.imageScale, y / mapState.imageScale)}
</Text>
</Animated.View>
))}
</View>
);
}
Я пробовал несколько вещей, чтобы попытаться уменьшить количество вызовов setState, но не дал очень хороших результатов с ним.
Что я могу сделать, чтобы ускорить это? Возможно переработка старых элементов? Разные подходы я мог бы использовать? Я хочу остаться в Экспо, но до сих пор я пытался использовать React Native Maps (моя карта не в нужном формате листов, не имею представления о сетках) и сам отображал ее с помощью GLView + Pixijs (не удалось получитьвход работает).