Skip to content

React

You can use the built-in Vite virtual module virtual:pwa-register/react for React which will return useState stateful values (useState<boolean>) for offlineReady and needRefresh.

警告

你需要将 workbox-window 作为 dev 依赖添加到你的 Vite 项目中

类型声明

提示

如果你的 TypeScript 构建时或 IDE 抱怨在导入时找不到模块或类型定义,请将以下内容添加到tsconfig.jsoncompilerOptions.types 数组中:

json
{
  "compilerOptions": {
    "types": ["vite-plugin-pwa/client"]
  }
}

或者你可以添加以下引用到任何 d.ts 文件中(例如,在 vite-env.d.tsglobal.d.ts 中):

ts
/// <reference types="vite-plugin-pwa/client" />

From version 0.14.5 you can also use types definition for react instead of vite-plugin-pwa/client, you can use:

json
{
  "compilerOptions": {
    "types": [
      "vite-plugin-pwa/react"
    ]
  }
}

Or you can add the following reference in any of your d.ts files (for example, in vite-env.d.ts or global.d.ts):

ts
/// <reference types="vite-plugin-pwa/react" />
ts
declare module 'virtual:pwa-register/react' {
  import type { Dispatch, SetStateAction } from 'react'
  import type { RegisterSWOptions } from 'vite-plugin-pwa/types'

  export type { RegisterSWOptions }

  export function useRegisterSW(options?: RegisterSWOptions): {
    needRefresh: [boolean, Dispatch<SetStateAction<boolean>>]
    offlineReady: [boolean, Dispatch<SetStateAction<boolean>>]
    updateServiceWorker: (reloadPage?: boolean) => Promise<void>
  }
}

Prompt for update

警告

The options provided to hooks are not reactive. Therefore, the callback references will be the first rendered options instead of the latest hook’s options. If you are doing complex logic with state changes, you will need to provide a stable reference function.

You can use this ReloadPrompt.tsx component:

ReloadPrompt.tsx
tsx
import React from 'react'
import './ReloadPrompt.css'

import { useRegisterSW } from 'virtual:pwa-register/react'

function ReloadPrompt() {
  const {
    offlineReady: [offlineReady, setOfflineReady],
    needRefresh: [needRefresh, setNeedRefresh],
    updateServiceWorker,
  } = useRegisterSW({
    onRegistered(r) {
      // eslint-disable-next-line prefer-template
      console.log('SW Registered: ' + r)
    },
    onRegisterError(error) {
      console.log('SW registration error', error)
    },
  })

  const close = () => {
    setOfflineReady(false)
    setNeedRefresh(false)
  }

  return (
    <div className="ReloadPrompt-container">
      { (offlineReady || needRefresh)
        && <div className="ReloadPrompt-toast">
            <div className="ReloadPrompt-message">
              { offlineReady
                ? <span>App ready to work offline</span>
                : <span>New content available, click on reload button to update.</span>
              }
            </div>
            { needRefresh && <button className="ReloadPrompt-toast-button" onClick={() => updateServiceWorker(true)}>Reload</button> }
            <button className="ReloadPrompt-toast-button" onClick={() => close()}>Close</button>
        </div>
      }
    </div>
  )
}

export default ReloadPrompt

and its corresponding ReloadPrompt.css styles file:

ReloadPrompt.css
css
.ReloadPrompt-container {
    padding: 0;
    margin: 0;
    width: 0;
    height: 0;
}
.ReloadPrompt-toast {
    position: fixed;
    right: 0;
    bottom: 0;
    margin: 16px;
    padding: 12px;
    border: 1px solid #8885;
    border-radius: 4px;
    z-index: 1;
    text-align: left;
    box-shadow: 3px 4px 5px 0 #8885;
    background-color: white;
}
.ReloadPrompt-toast-message {
    margin-bottom: 8px;
}
.ReloadPrompt-toast-button {
    border: 1px solid #8885;
    outline: none;
    margin-right: 5px;
    border-radius: 2px;
    padding: 3px 10px;
}

Periodic SW Updates

As explained in 定期更新 Service Worker , you can use this code to configure this behavior on your application with the virtual module virtual:pwa-register/react:

ts
import { useRegisterSW } from 'virtual:pwa-register/react'

const intervalMS = 60 * 60 * 1000

const updateServiceWorker = useRegisterSW({
  onRegistered(r) {
    r && setInterval(() => {
      r.update()
    }, intervalMS)
  }
})

The interval must be in milliseconds, in the example above it is configured to check the service worker every hour.

警告

这只适用于在导入任何虚拟模块或使用 workbox-window 模块时

因为 workbox-window 使用基于时间的 heuristic 算法来处理 service worker 更新,因此,如果您构建了自己的 service worker 并再次注册它,如果上次注册和本次注册之间的时间不足 1 分钟,那么workbox-window 将把 service worker update found 事件作为外部事件处理,因此可能会有很奇怪的行为(例如,如果使用 prompt ,将显示离线准备就绪的对话框,而不是显示新内容可用的对话框;如果使用 autoUpdate ,将显示离线准备就绪的对话框,然而它不应该显示)。

在MIT许可下发布.