React - отслеживаем видимость страниц

В этой статье мы создадим простой React компонент, который отслеживает “Page Visibility State.”

Офис "<a href="https://api.vc.ru/v2.8/redirect?to=https%3A%2F%2Fdigitalskynet.ru%2F&postId=45860" rel="nofollow noopener" target="_blank">Digital Skynet</a>"
Офис "Digital Skynet"

При создании веб-приложения вы можете столкнуться с ситуациями, когда нужно отследить текущее состояние видимости. Могут возникнуть ситуации когд нужно воспроизвести / приостановить эффект анимации или видео, уменьшить интенсивность или отследить поведение пользователя для аналитики.

На первый взгляд эта функция кажется довольно простой для реализации, но это не совсем так. Отслеживание активности пользователя довольно сложный процесс.

Есть Page Visibility API, который отлично работает в большинстве случаев, но не обрабатывает все возможные случаи неактивности вкладки браузера. Page Visibility API отправляет событие visibilitychange, чтобы listeners знали, что состояние видимости страницы изменилось. Он не запускает событие в некоторых случаях, если окно или соответствующая вкладка браузера скрыты из виду.

Чтобы обрабатывать некоторые из этих случаев, нам нужно использовать комбинацию событий focus и blur как в document, так и на window.

Начнем

Мы будем использовать Codesandbox для выполнения React приложения (вы также можете использовать create-react-app). Создадим небольшое приложение, в котором HTML5 элемент Video будет воспроизводиться только в том случае, если вкладка браузера находится в фокусе или активна, иначе оно будет приостановлено автоматически. Мы используем Video, так как это облегчит тестирование функций приложения.

React - отслеживаем видимость страниц

Создадим простой React класс и элемент video с его исходным кодом, принимающим URL-адрес, переданный с помощью src. Мы будем использовать новый ref API для присоединения ссылки к DOM-node video. Настроим video на автовоспроизведение, предполагая, что когда мы запустим приложение, страница будет активна.

Отметим, что Safari не позволяет автоматически воспроизводить элементы мультимедиа без взаимодействия с пользователем. Метод componentDidUpdate очень удобен при обработке эффектов при изменении свойства компонента. Поэтому здесь будем использовать этот метод для воспроизведения и приостановки видео на основе текущего значения this.props.active.

Различия в префиксах браузера не всегда удобны в использовании определенных API-интерфейсов, и Page Visibility API один из них. Мы создадим простую функцию утилиты, которая будет обрабатывать эти различия и возвращать нам единый API на основе браузера пользователя. Мы создадим и экспортируем эту функцию из pageVisibilityUtils.js в src directory.

React - отслеживаем видимость страниц

В этой функции будем использовать оператор if-else, чтобы вернуть API-интерфейс, специфичный для браузера. Видно, что мы добавляем префикс ms для Internet Explorer и префикс webkit для Webkit браузеров. Мы будем хранить нужный API в hidden и visibilityChange переменных и возвращать их из функции в виде простого объекта. Наконец экспортируем функцию.

Затем перейдем на наш основной компонент. Мы инкапсулируем всю логику отслеживания видимости страницы в используемом класс-компоненте React, используя шаблон Render Props. Создадим класс-компонент VisibilityManager. Этот компонент будет обрабатывать добавление и удаление всех событий на основе DOM listeners.

Начнем с импорта ранее созданной вспомогательной функции и ее вызова для получения правильных API-интерфейсов браузера. Затем создадим React компонент и инициализируем его состояние с одним единственным полем isVisible установленным в true. Это Boolean поле будет отвечать за состояние видимости страницы.

В componentDidMount мы добавим event listener к document для visibilitychange с помощью метода this.handleVisibilityChange в качестве обработчика. Также добавим event listener для событий focus и blur в document, а также элементе window. На этот раз мы установим this.forceVisibilityTrue и this.forceVisibilityFalse как обработчики для событий focus и blur.

React - отслеживаем видимость страниц

Затем мы создадим метод handleVisibilityChange, который принимает аргумент forceFlag. Аргумент forceFlag будет использоваться для определения того, вызван ли метод из-за события visibilitychange или событий focus и blur. Это происходит потому, что методы forceVisibilityTrue и forceVisibilityFalseничего не делают, кроме вызова метода handleVisibilityChange с истинным и ложным значением для forceFlag.

Внутри метода handleVisibilityChange сначала проверяем является ли значение аргумента forceFlag логическим (если он вызывается из обработчика события visibilitychange, то переданный аргумент будет объектом SyntheticEvent).

Если это Boolean, тогда мы проверяем истинно оно или ложно. Когда истинно, вызываем метод setVisibility с true или вызываем метод с false. Метод setVisibility использует this.setState метод для обновления значения isVisibleв состоянии компонента.

Если forceFlag не Boolean, мы проверяем значение скрытого атрибута в document и соответствующим образом вызываем метод setVisibility. Это завершает логику отслеживания состояния видимости страницы.

Чтобы сделать компонент многоразовым, мы используем паттерн Render Props. То есть вместо рендеринга компонента из метода render мы вызываем this.props.children как функцию с this.state.isVisible.

React - отслеживаем видимость страниц

Наконец, мы устанавливаем React приложение в DOM в файле index.js. Мы импортируем два компонента React VisibilityManager и Video и создаем компонент App, соединив их. Мы передаем функцию как дочерний элемент компонента VisibilityManager, который принимает на вход isVisible и передает его компоненту Video на выходе. Также передаем URL-адрес видео как src для компонента Video. Вот как мы применяем компонент VisiblityManager на основе Render Props. В конце используем метод ReactDOM.render для рендеринга приложения на DOM-node с идентификатором «root».

Заключение

Современные API-интерфейсы браузера становятся действительно мощными и используются для создания потрясающих вещей. Большинство из этих API являются обязательными по своей сути и могут быть сложными в работе. Полезно использовать паттерн Render Props для переноса этих API-интерфейсов в их собственные повторно-используемые React компоненты.

Адаптированный перевод статьи How to track page visibility in React using render props от Digital Skynet :)

3 комментария

А можно оторвать руки за скриншоты кода? Ну и плюс да, зачем это тут?

1

Почему не на Хабр?