SuhushinAS / renderless-components

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Renderless Components в React. Как интегрировать неинтегрируемое?

Вступление

intro

Привет DevPRO! Сегодня я хочу рассказать вам про Renderless Components в React.

about

Для начала - немного о себе: меня зовут Сухушин Александр. Я - Frontend-разработчик в компании Userstory (навести на ссылку). Наша компания занимается проектированием и разработкой сайтов и комплексных информационных систем для автоматизации бизнеса, (убрать наведение с сылки) а также решениями коммерческих и маркетинговых задач.

stack

Мы делаем фронтенд на React.

stack

В своём последнем проекте нам нужно было работать с картами, а также обновлнять состояние на клиенте по WebSocket. Мы использовали Leaflet, на данный момент - это самая известная OpenSource библиотека для работы с картами. Для работы с WebSocket мы использовали билиотеку Centrifuge. Основная проблема этих двух библиотек то, что у них нет реализации для React.

react−leaflet

На самом деле есть React-Leaflet, но нам нужно было использовать сторонние плагины, которые он не поддерживал и не давал нужной гибкости. Что же делать?

leaflet

Для начала давайте посмотрим, как работает сам LeafLet, заглянем в официальную документацию: Чтобы создать карту, нужно создать div, который будет выступать в качестве контейнера для карты. Далее в JavaScript нужно вызвать метод L.map(), куда передать идентификатор контейнера или ссылку на его узел DOM. Также, нужно спозиционировать карту, в данном случае задаются координаты центра и масштаб. И ещё нужно насторить Тайл-сервер - это сервер, который будет возвращать картинки для карты.

map

Мы можем реализовать это в React следующим образом: В методе render, мы срздаём div и сохраняем ссылку на него с помощью ref. В componentDidMount мы вызываем метод L.map(), куда передаём ссылку на созданый контейнер, и сохраняем экземпляр в state. В componentWillUnmount мы удаляем созданный экземпляр карты. Так же через контекст мы передаём дочерним элементам созданый экземпляр leaflet.

tile-layer

Тайл-сервер: render - null. В componentDidMount, мы добавляем слой тайл-сервера, в componentWillUnmount - его удаляем. В componentDidUpdate - удаляем старый слой и добавляем новый. добавление и удаление слоёв - это уже вызовы методов Leaflet, которые можно посмотреть в документации.

map-geo-json

Подобным же образом выводятся объекты на карте. На componentDidMount, мы добавляем слой, на componentWillUnmount - удаляем его. На componentDidUpdate - удаляем старый слой и добавляем новый.

geo-json

Для описания объектов на карте используется формат GeoJSON. По сути, это обычный JSON, с определённой структурой. Для примера, я описал несколько объектов:

map-view

С позиционированием немного посложнее: Самый простой способ - это задать координаты центра и масштаб, но по проекту требовалось позиционировать карту, чтобы у неё был максимальный масштаб, но при этом в экран попадали все объекты. В componentDidMount я вызываю метод fly(), который получает view - это объект или массив объектов в формате GeoJSON. Из view мы получаем bounds.

bounds

bounds - это минимальная прямоуголяная область, которая включает все объекты.

map-view-2

Если bounds - корректный - мы позиционируем карту на нём, иначе показываем весь мир. В componentDidUpdate я проверяю, изменился ли view, изменился ли bounds если да, вызываю fly(). И также я добавил обработчик измнения позиционирования карты, который вызывает onViewChange, если он был передан в props.

map-view-joke

Я вижу, вы уже немного устали от кода. На самом деле есть такая тема, когда долго смотришь на код (нажать картинку), код начинает смотреть на тебя.

map-usage

Давайте посмотрим пример, как это выглядит в использовании: Выводится компонент Map, а внутри него - TileLayer, View, и объекты на карте.

map-example

И, наконец, посмотрим на результат, можете перейти по этому коду: (подождать пару минут) Здесь мы можем менять позиционирование карты, при этом фиксируется текущее положение. Можем менять тайл сервер, например есть такой, и даже такой... Также можем отображать на карте разные объекты: например, маркер, где проходит DevPRO, маркер, где находится наш новый офис, и путь, между ними. При этом, как вы видите, карта автоматически позиционируется по выводимым объектам. (Закрыть Ctrl+W)

socket-centrifuge

Как вы заметили, во многих компонентах, я ничего не выводил, а пользовался только методами жизненного цикла. Такой подход я назвал Renderless Components. И он позволяет интегрирровать практически что угодно: Например так я интегрировал WebSocket: componentDidMount - я подключаюсь к серверу центрифуги, componentWillUnmount - отключаюсь, и передаю экзепляр центрифуги через контекст дочерним элементам.

socket-subscribe

Аналогично - компонент для подписки componentDidMount - подписывемся, componentWillUnmount - отписываемся. Во время подписки - регистрируем обработчик сообщений.

socket-usage

В использовании это выглядит вот так: Мы оборачиваем всё в компонент Centrifuge, куда передаём данные для подключения. Внутри выводим компонент Subscribe, куда передаём название канала и обработчик сообщения. По WebSocket мы будем получать координаты точки и выводить её на карте.

socket-example

Я подготовил пример, как по сокетам мы будем получать координаты точки (подождать пару минут):

questions

По этомим кодам ссылки на презентацию и исходный код примеров. На этом у меня всё, пожалуйста ваши вопросы.

About

License:Other


Languages

Language:HTML 100.0%