От Chrome до Safari: обнаружение дубликатов вкладок везде и управление ими

В этом сообщении блога мы рассмотрим фрагмент кода, который можно использовать для проверки наличия дубликатов вкладок в браузере, и расширим его для работы в разных браузерах и платформах с помощью интеграции с сервером.

Введение

Дублирование вкладок может быть проблематичным в определенных сценариях, например при работе с конфиденциальными данными или при попытке поддерживать приложение с одним экземпляром. Обнаружив и предотвратив дублирование вкладок, мы можем обеспечить лучший пользовательский опыт и сохранить целостность данных. Код, который мы будем обсуждать, предоставляет механизм для обнаружения дубликатов вкладок в одном и том же браузере.

Обзор кода

Начнем с изучения фрагмента кода:

import React, { useState, useEffect } from 'react';
import styled from 'styled-components';

const Container = styled.div`
  padding: 22px 24px 20px;
  background-color: white;
  border-radius: 3px;
  box-shadow: 0 15px 50px 0 rgba(0, 0, 0, 0.19), 0 12px 15px 0 rgba(0, 0, 0, 0.24);
  position: fixed;
  top: 40%;
  left: 50%;
  transform: translate(-50%);
  line-height: 1.4rem;
  width: 400px;
`;

const ButtonGroup = styled.div`
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding-top: 50px;
`;

const DuplicateTabChecker = ({ children, panelKey, panel }) => {
  const [duplicateTab, setDuplicate] = useState(null);

  useEffect(() => {
    localStorage.setItem(`${panelKey}_open`, Date.now());
    setDuplicate(false);
  }, []);

  useEffect(() => {
    const onLocalStorageEvent = (e) => {
      if (e.key === `${panelKey}_open`) {
        setDuplicate(true);
      }
    };

    window.addEventListener('storage', onLocalStorageEvent, false);

    return () => window.removeEventListener('storage', onLocalStorageEvent);
  }, []);

  if (duplicateTab === null) return null;

  if (duplicateTab) {
    return (
      <Container>
        <h2>The panel {panel} is open in another window.</h2>
        <p>Click "Use Here" to use the panel in this window.</p>
        <ButtonGroup>
          <button onClick={() => window.location.reload()}>Reload to Use Here</button>
        </ButtonGroup>
      </Container>
    );
  }

  return <>{children}</>;
};

export default DuplicateTabChecker;

Предоставленный фрагмент кода представляет собой компонент React, который проверяет наличие дубликатов вкладок в одном и том же браузере. Давайте разберем функциональность и посмотрим, как она работает.

Проверка дубликатов вкладок

Компонент DuplicateTabChecker обрабатывает логику проверки дубликатов вкладок. Вот как это работает:

  1. Компонент принимает три реквизита: children, panelKey и panel. Свойство children представляет контент, который должен отображаться, если нет повторяющихся вкладок. Свойство panelKey используется в качестве ключа в локальном хранилище для отслеживания состояния вкладки. Свойство panel представляет собой имя проверяемой панели или компонента.
  2. Внутри компонента мы определяем переменную состояния с именем duplicateTab, используя хук useState. Изначально установлено значение null.
  3. Мы используем хук useEffect с пустым массивом зависимостей, чтобы запускать код только один раз при монтировании компонента. Внутри этого эффекта мы устанавливаем текущую метку времени в локальном хранилище с помощью ключа ${panelKey}_open. Кроме того, мы устанавливаем состояние duplicateTab в false, чтобы указать, что дубликаты вкладок не обнаружены.
  4. Мы используем другой хук useEffect для прослушивания изменений в локальном хранилище. Когда происходит изменение, вызывается функция onLocalStorageEvent. Если ключ изменения соответствует ${panelKey}_open, это означает, что открыта другая вкладка с таким же ключом, и мы устанавливаем состояние duplicateTab на true.
  5. Мы добавляем прослушиватель событий для события 'storage' и вызываем функцию onLocalStorageEvent при возникновении события. Чтобы очистить прослушиватель событий, мы возвращаем функцию очистки в хуке useEffect, которая удаляет прослушиватель событий при размонтировании компонента.
  6. Если состояние duplicateTab равно null, мы возвращаем null. Это полезно для предотвращения рендеринга любого контента до завершения проверки дубликатов вкладок.
  7. Если состояние duplicateTab равно true, мы визуализируем компонент Container с соответствующим сообщением, включая имя panel. Мы также визуализируем компонент ButtonGroup с кнопкой для перезагрузки текущей страницы и используем текущую вкладку вместо дубликата.
  8. Если состояние duplicateTab равно false, мы визуализируем реквизит children, который представляет содержимое, которое будет отображаться, когда нет дубликатов вкладок.

Расширение на несколько браузеров и платформ

Хотя обсуждаемый нами код предназначен для работы в одном браузере, его можно расширить для работы в разных браузерах и платформах с помощью интеграции с сервером. Вот общий обзор подхода:

  1. Настройте сервер WebSocket, который может обрабатывать входящие подключения и сообщения от клиентов.
  2. Когда открывается новая вкладка, установите соединение WebSocket от клиентского приложения к серверу.
  3. После установления соединения WebSocket отправьте на сервер сообщение о том, что открыта новая вкладка. Включите соответствующую информацию, такую ​​как идентификатор вкладки или любой другой идентификатор.
  4. На сервере прослушивайте входящие сообщения WebSocket. Когда получено сообщение, указывающее на новую вкладку, добавьте подключение WebSocket к определенной группе или каналу, связанному с «панелью».
  5. Как только соединение WebSocket будет добавлено в группу, отправьте сообщение всей группе, уведомляющее другие вкладки об открытии новой вкладки. Включите необходимые данные, такие как идентификатор вкладки или любой другой идентификатор.
  6. На стороне клиента каждая вкладка должна прослушивать сообщения WebSocket в группе «панель». Когда получено сообщение, указывающее на новую вкладку, обновите дублирующийся статус вкладки на true.
  7. Обновите пользовательский интерфейс каждой вкладки, чтобы отразить повторяющийся статус. Например, отобразите сообщение или отключите определенные функции, чтобы предотвратить взаимодействие с повторяющимися вкладками.

Выполняя эти шаги и реализуя необходимые функции WebSocket, вы можете гарантировать, что при открытии новой вкладки она останется активной, а старые устаревшие вкладки не будут работать.

Интегрируя сервер в решение, вы можете синхронизировать информацию о вкладках в разных браузерах и платформах, обеспечивая единообразие работы и предотвращая дублирование вкладок независимо от используемого браузера или платформы.

Заключение

Обнаружение и обработка повторяющихся вкладок в одном и том же браузере может иметь решающее значение в определенных сценариях для обеспечения целостности данных и лучшего взаимодействия с пользователем. Фрагмент кода, который мы исследовали, предоставляет механизм для проверки дубликатов вкладок без интеграции с сервером. Преобразовав встроенные стили в стилизованные компоненты, мы улучшили удобство сопровождения и организацию кода. Кроме того, мы обсудили, как можно расширить код для работы в разных браузерах и платформах с помощью интеграции с сервером. Интегрируя сервер, вы можете обнаруживать дубликаты вкладок в нескольких браузерах и обеспечивать единообразие взаимодействия с пользователем.