Поговорим о том как можно использовать карты в приложении на RN бесплатно. О том какой ещё может быть структура
каталогов. Как можно сделать универсальный контейнер для компонентов. Чем могут быть полезны селекторы.
Структура каталогов. Как вариант - каждая фича (feature) в отдельной директории, чтобы не искать размазанные
по всему проекту файлы. Общие для всех только методы API. В нашем примере это директория map.
Не стану углубляться в настройку хранилища, подробный рассказ об этом уже был.
В исходной точке подключим само хранилище (store) и экран приложения с картой.
А вот и первый лайфхак. Если есть необходимость использовать универсальный
контейнер без привязки к конкретным компонентам (не наш случай, но всё же),
можно опираться на render-props или вообще
склонировать компонент, который будет передан контейнеру.
Смотрим
По поводу английского языка можно не волноваться — всегда будет
выбран язык, установленный в системе.
Смена маркеров при прокрутке карты
Теперь представим, что у нас есть API, где при смене региона мы получаем новые данные.
А вот если просто сдвигать область на карте, данные не меняются: API отдаёт весь внушительный
список маркеров, что у него есть. Выводить сразу все маркеры нельзя — скажется
на производетельности. В этом случае нас выручат селекторы.
Для рассчёта ближайших маркеров понадобится библиотека: например, geolib.
// MapContainerimport React,{ useEffect, ReactElement, useCallback }from'react'import{ useDispatch, useSelector }from'react-redux'import mapsSlice,{ fetchMapEntities }from'./store'import{ mapLoadingSelector, mapMarkersSelector, mapRegionSelector }from'./selectors'import{ IRegion }from'./types'const{ changeRegion }= mapsSlice.actions
typeProps={
children: ReactElement
}constMapContainer=({ children }: Props)=>{// забираем данные из хранилищаconst dispatch =useDispatch()const markers =useSelector(mapMarkersSelector)const region =useSelector(mapRegionSelector)const isLoading =useSelector(mapLoadingSelector)const handleGetMapEntities =useCallback(async()=>awaitdispatch(fetchMapEntities()),[dispatch],)// получить от карты точное местоположение и сохранить егоconstonRegionChangeComplete=(coordinate: IRegion)=>{dispatch(changeRegion(coordinate))}/*
при посещении экрана дёргаем API один раз
можно проверять есть ли уже данные
или получать новые данные при смене локации
это остаётся на усмотрение читателя
*/useEffect(()=>{handleGetMapEntities()},[handleGetMapEntities])// передать данные в дочерний компонентconst CloneChildren = React.cloneElement(children,{
markers,
region,
isLoading,
onRegionChangeComplete,})return<>{CloneChildren}</>}exportdefault MapContainer
Теперь MapView получает данные из контейнера и код компонента немного изменится
(не буду приводить код полностью, не забудьте импортировать все компоненты из react-native).
Для того, чтобы уменьшить время отклика и повысить производительность при перерисовке
маркеров, поставьте библиотеку throttle-debounce. Код в MapContainer
изменится таким образом:
Не упомнишь какие из маркеров были нажаты. Здорово было бы отражать их состояние: обычный,
активный или уже просмотренный. Как может выглядеть реализация?
Нам нужен новый экшен setMarkerAction для манипулирования состоянием маркера.
Импортируем его из группы экшенов и отдадим дочернему компоненту.