DEV Community

terrierscript
terrierscript

Posted on

Append reload notice on create-react-app & registerServiceWorker.js

create-react-app has registerServiceWorker.js by default.

I knew that this feature enable offline caching, but I felt it was hard to understand how to handle it (and sometime disalbed it).

I try to make show reload modal example like this.


screenshot

Source Code


1. Prepare

By Default create-react-app, is not easy for local service-worker debugging.

I eject create-react-app and install serve. ( and need disable serve cache-control. )

{
  "scripts": {
    "start":
      "NODE_ENV=production webpack --config config/webpack.config.prod.js --watch",
    "static": "serve -c 0 -s build -o --local"
  }
}

And start like this.

$ yarn start & yarn static

2. Append event dispatching when onupdatefound

When ServiceWorker detects an update, onupdatefound of registerServiceWorker is executed, and I append distpatch event here.

registration.onupdatefound = () => {
  const installingWorker = registration.installing;
    installingWorker.onstatechange = () => {
        if (navigator.serviceWorker.controller) {
          // At this point, the old content will have been purged and
          // the fresh content will have been added to the cache.
          // It's the perfect time to display a "New content is
          // available; please refresh." message in your web app.
          console.log("New content is available; please refresh.");

          // Append dispatch event
          const event = new Event("newContentAvailable");
          window.dispatchEvent(event);
        } else {
           :

In next version, service worker script got config.onUpdate callback.
We do not need to add the code directly to registerServiceWorker.js

2. Create <ReloadModal>

Next, I append <ReloadModal> that catch global custom newContentAvailable event.


// Main App
class App extends Component {
  render() {
    return (
      <div className="App">
        <ReloadModal />
            :
      </div>
    );
  }
}

class ReloadModal extends Component {
  state = {
    show: false
  };
  componentDidMount() {
    // Handle global event.
    window.addEventListener("newContentAvailable", () => {
      this.setState({
        show: true
      });
    });
  }
  onClick = () => {
    // Reload when modal click.
    window.location.reload(window.location.href);
  };
  render() {
    if (!this.state.show) {
      return null;
    }
    // <Modal> is common fixed component.
    return (
      <Modal onClick={this.onClick}>
        <span> New Content Available!please reload </span>
      </Modal>
    );
  }
}

Conclusion

After this, I can got result like screenshot.

But I'm not confident in this implementation.
Please tell me if more better way.

Top comments (4)

Collapse
 
toneko profile image
Nano •

Hi, what happens if the user has one more instance of the app open and we try to reload the page?

Collapse
 
terrierscript profile image
terrierscript •

Sorry, I'm not try that...
But I suspect that effect both browser because cache stored in brower storage.

Collapse
 
eligoldberg profile image
Eli Golderg •

Hi, great post !
What is the eject for?

Collapse
 
terrierscript profile image
terrierscript •

Thank you.

Eject mean execute $ npm run eject
It's need when article posted timing, but currently, it's may not need.