Reset React Native WebView to initial url

Andrei Pfeiffer
2 min readFeb 26, 2018

--

React Native’s WebView is a great component that enables a ton of features. However, there are a few things that needs some extra work to make them work.

One of these things is resetting the WebView to the initial url once the user navigated away, to other urls.

Solution #1: Using refs

One options would be to use the WebView ref methods to control the navigation:

class App extends Component {
goBack = () => {
this.webview.goBack();
};
render() {
return (
<WebView
ref={r => this.webview = r}
source={{ uri: yourInitialUrl }}
/>
);
}
}

Ok, but if the user navigated X number of pages within the WebView, then we have to keep track of that somehow, and call this.webview.goBack(); X number of times, right? Right. Well, not very nice, isn’t it precious?

What about reload() ?

There’s also a this.webview.reload(); method that reloads the page. However, that doesn’t help, because it reloads the current page, not the one that was loaded initially.

Solution #2: Forcing a re-render

What if we could trigger the WebView component to render again? That should reset everything, right?

One approach would be to abuse React’skey prop. Changing its value will cause a re-render of that component:

class Foo extends Component {
state = {
key: 1
};

resetWebViewToInitialUrl = () => {
this.setState({
key: this.state.key + 1
});
};

render() {
return (
<WebView
key={ this.state.key }
source={{ uri: yourInitialUrl }}
/>
);
}
}

Now, if you call this.resetWebViewToInitialUrl() it will force the WebView component to re-render, causing it to reset its internal url.

Optimizing reloads

It would make more sense to reset it only when the url changes. To do this:

  • we listen to WebView navigation state changes
  • check if the url really changed
  • set an internal flag when it does
  • reset only when the flag is on
class Foo extends Component {
state = {
key: 1,
isWebViewUrlChanged: false
};

resetWebViewToInitialUrl = () => {
if (this.state.isWebViewUrlChanged) {
this.setState({
key: this.state.key + 1,
isWebViewUrlChanged: false
});
}
};

setWebViewUrlChanged = webviewState => {
if (webviewState.url !== yourInitialUrl) {
this.setState({ isWebViewUrlChanged: true });
}
};

render() {
return (
<WebView
key={ this.state.key }
source={{ uri: yourInitialUrl }}
onNavigationStateChange={ this.setWebViewUrlChanged }
/>
);
}
}

What about React’s forceUpdate() ?

There’s a built-in method in React, called forceUpdate() that will force a component to re-render. However, calling it will re-render only the Foo component, not its entire subtree as well.

Our WebView component, being a descendant of Foo, will not be re-rendered, because nothing has changed.

Disclaimer

I know this solution is hacky, but it’s the only one I could find. If you know a more elegant solution, I would be more than happy to hear it.

Feel free to get in touch in the comments section or on Twitter @pfeiffer_andrei.

--

--

Andrei Pfeiffer

code designer, tim.js meetup organizer, speaker, trainer