@sasha_jarvi

Как исправить проблему с центрированием карты (react-native-maps) при тапе на маркер?

Имеется следующий компонент карты, использующий react-native-maps:
const TasksMapScreen: React.FunctionComponent<Props> = () => {
  const route = useRoute();

  const tasks = [
    {
      id: 5602481,
      category: 'lights',
      text: 'задача 1',
      location: 'адрес 1',
      latlng: {
        latitude: 54.1925489,
        longitude: 37.6705917,
      },
      distance: 200,
      date: '08.06.2019',
      price: 300,
      isResolved: false,
      reworkings: 0,
    },
    {
      id: 5602482,
      category: 'garbage',
      text: 'задача 2',
      location: 'адрес 2',
      latlng: {
        latitude: 54.1541381,
        longitude: 37.5843054,
      },
      distance: 200,
      date: '08.06.2019',
      price: 0,
      deadline: '18.06.2019',
      isResolved: false,
      reworkings: 0,
    },
    {
      id: 5602483,
      category: 'garbage',
      text: 'задача 3',
      location: 'адрес 3',
      latlng: {
        latitude: 54.1879952,
        longitude: 37.5988459,
      },
      distance: 200,
      date: '08.06.2019',
      price: 0,
      deadline: '18.06.2019',
      isOverdue: true,
      isResolved: false,
      reworkings: 0,
    },
    {
      id: 5602484,
      category: 'lights',
      text: 'задача 4',
      location: 'адрес 4',
      latlng: {
        latitude: 54.1571578,
        longitude: 37.5970531,
      },
      distance: 200,
      date: '08.06.2019',
      price: 0,
      deadline: '18.06.2019',
      rating: 5,
      isResolved: true,
      reworkings: 2,
    },
    {
      id: 5602489,
      category: 'lights',
      text: 'адрес 5',
      location: 'задача 5',
      latlng: {
        latitude: 54.1886121,
        longitude: 37.5982382,
      },
      distance: 200,
      date: '08.06.2019',
      price: 0,
      isResolved: false,
      reworkings: 0,
    },
  ];

  const tasksObj = tasks.reduce((acc, task) => {
    acc[task.id] = task;
    return acc;
  }, {});

  const tasksFirstId = Object.keys(tasksObj)[0];
  const initialMarkerLatlng = tasksObj[tasksFirstId].latlng;
  const taskId = route.params?.taskId;

  const [zoom, setZoom] = useState(14);
  const [task, selectTask] = useState(null);

  const region = {
    ...initialMarkerLatlng,
    latitudeDelta: 0.0922,
    longitudeDelta: 0.0421,
  };

  const mapView = useRef(null);

  useEffect(() => {
    if (taskId) {
      selectTask(taskId);
    }

    if (mapView.current) {
      mapView.current?.animateCamera(
        {
          center: tasksObj[task].latlng,
          zoom: 15,
        },
        1000,
      );
    }
  }, [taskId, task, tasksObj]);

  return (
    <View style={styles.container}>
      <MapView
        ref={mapView}
        style={styles.map}
        minZoomLevel={zoom}
        maxZoomLevel={zoom}
        showsCompass={false}
        initialRegion={region}>
        {Object.values(tasksObj).map((task) => (
          <Marker
            coordinate={task.latlng}
            title=""
            key={task.id}
            onPress={() => selectTask(task.id)}>
            <TaskMarker
              category={task.category}
              price={task.price}
              isResolved={task.isResolved}
              reworkings={task.reworkings}
            />
          </Marker>
        ))}
      </MapView>
    </View>
  );
};


Из другого компонента приходит свойство id, на основе которого выбирается задача, на маркере которой происходит центрирование карты. С этим аспектом все в порядке. Однако смена стейта и центрирование должно также происходить и при тапе на маркер задачи, чего в данный момент нет. Полагаю, что дело в первых трех строчках внутри useEffect()

if (taskId) {
      selectTask(taskId);
    }


Однако при их удалении перестает работать центрирование. Вынос selectTask(taskId) вызывает ошибку "Too many re-renders". Как решить проблему смены стейта и последующего центрирования при тапе на маркер?
  • Вопрос задан
  • 239 просмотров
Решения вопроса 1
@sasha_jarvi Автор вопроса
Изменил код таким образом - добавил в код второй useEffect() для изменения стейта task на основе приходящего id, в то время как первый useEffect() остается отвечать за центрирование карты на основе имеющегося task:

const [zoom, setZoom] = useState(14);
  const [task, selectTask] = useState(undefined);

  const mapView = useRef(null);

  useEffect(() => {
    if (task) {
      if (mapView.current) {
        mapView.current?.animateCamera(
          {
            center: task.latlng,
            zoom: 15,
          },
          1000,
        );
      }
    }
  }, [task]);

  useEffect(() => {
    if (route.params?.taskId) {
      // @ts-ignore
      selectTask(tasks.find((t) => t.id === route.params.taskId));
    }
  }, [route.params]);

  return (
    <View style={styles.container}>
      <MapView
        ref={mapView}
        style={styles.map}
        minZoomLevel={zoom}
        maxZoomLevel={zoom}
        showsCompass={false}
        initialRegion={region}
        onPress={() => selectTask(undefined)}>
        {tasks.map((task) => (
          <Marker
            coordinate={task.latlng}
            title=""
            key={task.id}
            // @ts-ignore
            onPress={() => selectTask(task)}>
            <TaskMarker
              category={task.category}
              price={task.price}
              isResolved={task.isResolved}
              reworkings={task.reworkings}
            />
          </Marker>
        ))}
      </MapView>
    </View>
  );
};
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы