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
 
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.

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.