Reactjs 在服务人员更新时创建react应用程序重新加载

Reactjs 在服务人员更新时创建react应用程序重新加载,reactjs,service-worker,create-react-app,Reactjs,Service Worker,Create React App,我想修改创建react app服务人员,并实现弹出消息,如果新的服务人员准备好激活,该消息将要求用户更新app。我几乎完成了解决方案,但有一个陷阱。我想在用户确认service worker update弹出窗口时重新加载应用程序,因此我在register功能的末尾添加了一些编码,请参见以下内容: export default function register(config) { if (process.env.NODE_ENV === "production" && "s

我想修改
创建react app
服务人员,并实现弹出消息,如果新的服务人员准备好激活,该消息将要求用户更新app。我几乎完成了解决方案,但有一个陷阱。我想在用户确认service worker update弹出窗口时重新加载应用程序,因此我在
register
功能的末尾添加了一些编码,请参见以下内容:

export default function register(config) {
  if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) {
    // The URL constructor is available in all browsers that support SW.
    const publicUrl = new URL(process.env.PUBLIC_URL, window.location)
    if (publicUrl.origin !== window.location.origin) {
      // Our service worker won't work if PUBLIC_URL is on a different origin
      // from what our page is served on. This might happen if a CDN is used to
      // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
      return
    }

    window.addEventListener("load", () => {
      const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`

      if (isLocalhost) {
        // This is running on localhost. Lets check if a service worker still exists or not.
        checkValidServiceWorker(swUrl, config)

        // Add some additional logging to localhost, pointing developers to the
        // service worker/PWA documentation.
        navigator.serviceWorker.ready.then(() => {
          console.log(
            "This web app is being served cache-first by a service " +
              "worker."
          )
        })
      } else {
        // Is not local host. Just register service worker
        registerValidSW(swUrl, config)
      }

      let preventDevToolsReloadLoop
      navigator.serviceWorker.addEventListener("controllerchange", function() {
        // ensure refresh is called only once
        if (preventDevToolsReloadLoop) {
          return
        }

        preventDevToolsReloadLoop = true
        console.log("reload")
        window.location.reload(true)
      })
    })
  }
}

但问题是,当还没有任何服务人员时,它也会在首次访问时重新加载应用程序。如何解决此问题?

尝试在installingWorker.state=='installed'中添加重新加载功能。

     if (installingWorker.state === 'installed') {
        if (navigator.serviceWorker.controller) {
          // do something ..
        }
      }

更新到
react脚本
^3.2.0。验证您是否拥有新版本的serviceWorker.ts或.js。旧的调用为
registerServiceWorker.ts
,并且register函数不接受配置对象。请注意,此解决方案只有在不延迟加载的情况下才能正常工作

然后在index.tsx中:

  serviceWorker.register({
    onUpdate: registration => {
      alert('New version available!  Ready to update?');
      if (registration && registration.waiting) {
        registration.waiting.postMessage({ type: 'SKIP_WAITING' });
      }
      window.location.reload();
    }
  });
最新版本的ServiceWorker.ts
register()
函数接受带有回调函数的配置对象,我们可以在其中处理升级。如果我们发布消息
SKIP_WAITING
,这会告诉服务人员停止等待,并在下次刷新后继续加载新内容。在本例中,我使用javascript警报通知用户。请用定制的烤面包片代替这个

postMessage
功能之所以有效,是因为CRA正在使用
workbox网页包插件
,其中包括一个
跳过等待
侦听器

有关服务人员的更多信息

好向导:

讨论服务工作者缓存的CRA问题:

如果您没有使用CRA,可以直接使用workbox:

完成:

由于您可能希望在检测到更新后询问用户,而不是简单的
警报
,因此您需要确保
注册
对象在React的组件树中可用,并将其保存以在用户接受更新后使用(例如,通过单击按钮)

作为一个选项,在组件中,您可以在全局对象(如
document
)上创建自定义事件侦听器,并在
onUpdate
回调传递给
serviceWorker.register()
时触发此事件,将
重新注册
对象作为额外数据传递给它

这正是我最近发表的文章所做的(一些自我宣传)。要使用它,您只需:

  • 将其添加到依赖项:
  • index.js中使用它:
从'@3m1/service worker updater'导入{onServiceWorkerUpdate};
// ...
//较新的Create React应用程序版本中有一些命名更改
serviceWorkerRegistration.register({
onUpdate:onServiceWorkerUpdate
});
  • 在某些React组件中使用它:
从“React”导入React;
从'@3m1/ServiceWorkerUpdater'导入{withServiceWorkerUpdater};
常量更新程序=(道具)=>{
const{newServiceWorkerDetected,onLoadNewServiceWorkerAccept}=props;
return newServiceWorkerDetected(
检测到新版本。
更新!
):null;//如果没有可用的更新,则不渲染任何内容
}
使用ServiceWorkerUpdater(更新程序)导出默认值;

在本地状态下将preventDevToolsReloadLoop设置为true如何。在导出默认函数寄存器(config){
我已经解决了它,但是忘了发布解决方案,谢谢!:-)非常干净的解决方案!谢谢!
yarn add @3m1/service-worker-updater
import React from 'react';
import { withServiceWorkerUpdater } from '@3m1/service-worker-updater';

const Updater = (props) => {
  const {newServiceWorkerDetected, onLoadNewServiceWorkerAccept} = props;
  return newServiceWorkerDetected ? (
    <>
      New version detected.
      <button onClick={ onLoadNewServiceWorkerAccept }>Update!</button>
    </>
  ) : null; // If no update is available, render nothing
}

export default withServiceWorkerUpdater(Updater);