Browse Source

Adds guide for intercepting hash URL changes

Jamon Holmgren 5 years ago
parent
commit
745dc5992e
2 changed files with 63 additions and 22 deletions
  1. 61
    22
      docs/Guide.md
  2. 2
    0
      docs/Reference.md

+ 61
- 22
docs/Guide.md View File

@@ -14,7 +14,6 @@ _This guide is currently a work in progress._
14 14
 - [Add support for File Download](Guide.md#add-support-for-file-download)
15 15
 - [Communicating between JS and Native](Guide.md#communicating-between-js-and-native)
16 16
 
17
-
18 17
 ### Basic inline HTML
19 18
 
20 19
 The simplest way to use the WebView is to simply pipe in the HTML you want to display. Note that setting an `html` source requires the [originWhiteList](Reference.md#originWhiteList) property to be set to `['*']`.
@@ -48,9 +47,7 @@ import { WebView } from 'react-native-webview';
48 47
 class MyWeb extends Component {
49 48
   render() {
50 49
     return (
51
-      <WebView
52
-        source={{uri: 'https://facebook.github.io/react-native/'}}
53
-      />
50
+      <WebView source={{ uri: 'https://facebook.github.io/react-native/' }} />
54 51
     );
55 52
   }
56 53
 }
@@ -71,7 +68,7 @@ class MyWeb extends Component {
71 68
     return (
72 69
       <WebView
73 70
         ref={ref => (this.webview = ref)}
74
-        source={{uri: 'https://facebook.github.io/react-native/'}}
71
+        source={{ uri: 'https://facebook.github.io/react-native/' }}
75 72
         onNavigationStateChange={this.handleWebViewNavigationStateChange}
76 73
       />
77 74
     );
@@ -87,7 +84,7 @@ class MyWeb extends Component {
87 84
     //   canGoForward?: boolean;
88 85
     // }
89 86
     const { url } = newNavState;
90
-    if (!url) return
87
+    if (!url) return;
91 88
 
92 89
     // handle certain doctypes
93 90
     if (url.includes('.pdf')) {
@@ -112,10 +109,48 @@ class MyWeb extends Component {
112 109
       const redirectTo = 'window.location = "' + newURL + '"';
113 110
       this.webview.injectJavaScript(redirectTo);
114 111
     }
115
-  }
112
+  };
116 113
 }
117 114
 ```
118 115
 
116
+#### Intercepting hash URL changes
117
+
118
+While `onNavigationStateChange` will trigger on URL changes, it does not trigger when only the hash URL ("anchor") changes, e.g. from `https://example.com/users#list` to `https://example.com/users#help`.
119
+
120
+You can inject some JavaScript to wrap the history functions in order to intercept these hash URL changes.
121
+
122
+```jsx
123
+<WebView
124
+  source={{ uri: someURI }}
125
+  injectedJavaScript={`
126
+    (function() {
127
+      function wrap(fn) {
128
+        return function wrapper() {
129
+          var res = fn.apply(this, arguments);
130
+          window.ReactNativeWebView.postMessage('navigationStateChange');
131
+          return res;
132
+        }
133
+      }
134
+
135
+      history.pushState = wrap(history.pushState);
136
+      history.replaceState = wrap(history.replaceState);
137
+      window.addEventListener('popstate', function() {
138
+        window.ReactNativeWebView.postMessage('navigationStateChange');
139
+      });
140
+    })();
141
+
142
+    true;
143
+  `}
144
+  onMessage={({ nativeEvent: state }) => {
145
+    if (state.data === 'navigationStateChange') {
146
+      // Navigation state updated, can check state.canGoBack, etc.
147
+    }
148
+  }}
149
+/>
150
+```
151
+
152
+Thanks to [Janic Duplessis](https://github.com/react-native-community/react-native-webview/issues/24#issuecomment-483956651) for this workaround.
153
+
119 154
 ### Add support for File Upload
120 155
 
121 156
 ##### iOS
@@ -123,18 +158,21 @@ class MyWeb extends Component {
123 158
 For iOS, all you need to do is specify the permissions in your `ios/[project]/Info.plist` file:
124 159
 
125 160
 Photo capture:
161
+
126 162
 ```
127 163
 <key>NSCameraUsageDescription</key>
128 164
 <string>Take pictures for certain activities</string>
129 165
 ```
130 166
 
131 167
 Gallery selection:
168
+
132 169
 ```
133 170
 <key>NSPhotoLibraryUsageDescription</key>
134 171
 <string>Select pictures for certain activities</string>
135 172
 ```
136 173
 
137 174
 Video recording:
175
+
138 176
 ```
139 177
 <key>NSMicrophoneUsageDescription</key>
140 178
 <string>Need microphone access for recording videos</string>
@@ -143,6 +181,7 @@ Video recording:
143 181
 ##### Android
144 182
 
145 183
 Add permission in AndroidManifest.xml:
184
+
146 185
 ```xml
147 186
 <manifest ...>
148 187
   ......
@@ -173,7 +212,7 @@ WebView.isFileUploadSupported().then(res => {
173 212
 
174 213
 ### Multiple Files Upload
175 214
 
176
-You can control __single__ or __multiple__ file selection by specifing the [`multiple`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#multiple) attribute on your `input` element:
215
+You can control **single** or **multiple** file selection by specifing the [`multiple`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#multiple) attribute on your `input` element:
177 216
 
178 217
 ```
179 218
 // multiple file selection
@@ -190,6 +229,7 @@ You can control __single__ or __multiple__ file selection by specifing the [`mul
190 229
 For iOS, all you need to do is specify the permissions in your `ios/[project]/Info.plist` file:
191 230
 
192 231
 Save to gallery:
232
+
193 233
 ```
194 234
 <key>NSPhotoLibraryAddUsageDescription</key>
195 235
 <string>Save pictures for certain activities.</string>
@@ -225,9 +265,9 @@ To accomplish this, React Native WebView exposes three different options:
225 265
 This is a script that runs immediately after the web page loads for the first time. It only runs once, even if the page is reloaded or navigated away.
226 266
 
227 267
 ```jsx
228
-import React, { Component } from "react";
229
-import { View } from "react-native";
230
-import { WebView } from "react-native-webview";
268
+import React, { Component } from 'react';
269
+import { View } from 'react-native';
270
+import { WebView } from 'react-native-webview';
231 271
 
232 272
 export default class App extends Component {
233 273
   render() {
@@ -241,7 +281,7 @@ export default class App extends Component {
241 281
         <WebView
242 282
           source={{
243 283
             uri:
244
-              "https://github.com/react-native-community/react-native-webview"
284
+              'https://github.com/react-native-community/react-native-webview',
245 285
           }}
246 286
           injectedJavaScript={runFirst}
247 287
         />
@@ -255,7 +295,7 @@ This runs the JavaScript in the `runFirst` string once the page is loaded. In th
255 295
 
256 296
 <img alt="screenshot of Github repo" width="200" src="https://user-images.githubusercontent.com/1479215/53609254-e5dc9c00-3b7a-11e9-9118-bc4e520ce6ca.png" />
257 297
 
258
-*Under the hood*
298
+_Under the hood_
259 299
 
260 300
 > On iOS, `injectedJavaScript` runs a method on WKWebView called `evaluateJavaScript:completionHandler:`
261 301
 > On Android, `injectedJavaScript` runs a method on the Android WebView called `evaluateJavascriptWithFallback`
@@ -265,9 +305,9 @@ This runs the JavaScript in the `runFirst` string once the page is loaded. In th
265 305
 While convenient, the downside to the previously mentioned `injectedJavaScript` prop is that it only runs once. That's why we also expose a method on the webview ref called `injectJavaScript` (note the slightly different name!).
266 306
 
267 307
 ```jsx
268
-import React, { Component } from "react";
269
-import { View } from "react-native";
270
-import { WebView } from "react-native-webview";
308
+import React, { Component } from 'react';
309
+import { View } from 'react-native';
310
+import { WebView } from 'react-native-webview';
271 311
 
272 312
 export default class App extends Component {
273 313
   render() {
@@ -286,7 +326,7 @@ export default class App extends Component {
286 326
           ref={r => (this.webref = r)}
287 327
           source={{
288 328
             uri:
289
-              "https://github.com/react-native-community/react-native-webview"
329
+              'https://github.com/react-native-community/react-native-webview',
290 330
           }}
291 331
         />
292 332
       </View>
@@ -299,7 +339,7 @@ After 3 seconds, this code turns the background blue:
299 339
 
300 340
 <img alt="Screenshot of app showing injected javascript" width="200" src="https://user-images.githubusercontent.com/1479215/53670433-93a98280-3c2f-11e9-85a5-0e4650993817.png" />
301 341
 
302
-*Under the hood*
342
+_Under the hood_
303 343
 
304 344
 > On iOS, `injectJavaScript` calls WKWebView's `evaluateJS:andThen:`
305 345
 > On Android, `injectJavaScript` calls Android WebView's `evaluateJavascriptWithFallback` method
@@ -313,9 +353,9 @@ You _must_ set `onMessage` or the `window.ReactNativeWebView.postMessage` method
313 353
 `window.ReactNativeWebView.postMessage` only accepts one argument which must be a string.
314 354
 
315 355
 ```jsx
316
-import React, { Component } from "react";
317
-import { View } from "react-native";
318
-import { WebView } from "react-native-webview";
356
+import React, { Component } from 'react';
357
+import { View } from 'react-native';
358
+import { WebView } from 'react-native-webview';
319 359
 
320 360
 export default class App extends Component {
321 361
   render() {
@@ -349,4 +389,3 @@ export default class App extends Component {
349 389
 This code will result in this alert:
350 390
 
351 391
 <img alt="Alert showing communication from web page to React Native" width="200" src="https://user-images.githubusercontent.com/1479215/53671269-7e822300-3c32-11e9-9937-7ddc34ba8af3.png" />
352
-

+ 2
- 0
docs/Reference.md View File

@@ -369,6 +369,8 @@ title
369 369
 url
370 370
 ```
371 371
 
372
+Note that this method will not be invoked on hash URL changes (e.g. from `https://example.com/users#list` to `https://example.com/users#help`). There is a workaround for this that is described [in the Guide](Guide.md#intercepting-hash-url-changes).
373
+
372 374
 ---
373 375
 
374 376
 ### `originWhitelist`