From b464d70de95b431fc76e3d7ad9fd9a673639fd94 Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Sun, 1 Dec 2024 15:05:16 +0800 Subject: [PATCH] fix: prevent reload by adding SCU fixes #75 --- src/pages/WikiWebView/CustomWebview.tsx | 14 +++++++++----- src/pages/WikiWebView/WikiViewer.tsx | 13 ++++++------- .../WikiWebView/useStreamChunksToWebView/index.ts | 14 +++++++------- src/pages/WikiWebView/useTiddlyWiki.ts | 5 +---- src/services/WikiHookService/hooks.ts | 14 +++++++++----- src/services/registerServiceOnWebView.ts | 15 +++++++++++---- 6 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/pages/WikiWebView/CustomWebview.tsx b/src/pages/WikiWebView/CustomWebview.tsx index 5c88829..7b981e1 100644 --- a/src/pages/WikiWebView/CustomWebview.tsx +++ b/src/pages/WikiWebView/CustomWebview.tsx @@ -1,21 +1,25 @@ -import React, { MutableRefObject, PureComponent } from 'react'; +import React, { Component, MutableRefObject } from 'react'; import { Text } from 'react-native-paper'; import { WebView, WebViewMessageEvent } from 'react-native-webview'; -import type { WebViewErrorEvent, WebViewNavigationEvent } from 'react-native-webview/lib/RNCWebViewNativeComponent'; import { FAKE_USER_AGENT } from '../../constants/webview'; interface CustomWebViewProps { backgroundColor: string; injectedJavaScript: string; - onLoadEnd: (event: WebViewNavigationEvent | WebViewErrorEvent) => void; - onLoadStart: () => void; + onLoadEnd?: () => void; + onLoadStart?: () => void; onMessageReference: MutableRefObject<(event: WebViewMessageEvent) => void>; preferredLanguage: string | undefined | null; + reloadingKey: string | number; triggerFullReload: () => void; webViewReference: MutableRefObject; } -export class CustomWebView extends PureComponent { +export class CustomWebView extends Component { + shouldComponentUpdate(nextProps: CustomWebViewProps) { + return this.props.reloadingKey !== nextProps.reloadingKey; + } + render() { const { backgroundColor, diff --git a/src/pages/WikiWebView/WikiViewer.tsx b/src/pages/WikiWebView/WikiViewer.tsx index 0ec9561..18ff09a 100644 --- a/src/pages/WikiWebView/WikiViewer.tsx +++ b/src/pages/WikiWebView/WikiViewer.tsx @@ -66,7 +66,7 @@ export function WikiViewer({ wikiWorkspace, webviewSideReceiver, quickLoad }: Wi * Register service JSB to be `window.service.xxxService`, for plugin in webView to call. */ const [webViewReference, onMessageReference, registerWikiStorageServiceOnWebView, servicesOfWorkspace] = useRegisterService(wikiWorkspace); - useSetWebViewReferenceToService(servicesOfWorkspace.wikiHookService, webViewReference); + useSetWebViewReferenceToService(servicesOfWorkspace, webViewReference); // TODO: goback not seem to working // useHandleGoBack(webViewReference); /** @@ -83,12 +83,12 @@ export function WikiViewer({ wikiWorkspace, webviewSideReceiver, quickLoad }: Wi triggerFullReload(); } }, [triggerFullReload, webViewKeyToReloadAfterRecycleByOS]); - servicesOfWorkspace.wikiHookService.setLatestTriggerFullReloadCallback(triggerFullReload); + servicesOfWorkspace.current?.wikiHookService?.setLatestTriggerFullReloadCallback?.(triggerFullReload); useEffect(() => { console.log('resetWebviewReceiverReady on webViewKeyToReloadAfterRecycleByOS and init'); - servicesOfWorkspace.wikiHookService.resetWebviewReceiverReady(); + servicesOfWorkspace.current?.wikiHookService?.resetWebviewReceiverReady?.(); void backgroundSyncService.updateServerOnlineStatus(); - }, [servicesOfWorkspace.wikiHookService, webViewKeyToReloadAfterRecycleByOS]); + }, [servicesOfWorkspace, webViewKeyToReloadAfterRecycleByOS]); const { loadHtmlError, loading, streamChunksToWebViewPercentage } = useTiddlyWiki( wikiWorkspace, loaded, @@ -127,7 +127,6 @@ export function WikiViewer({ wikiWorkspace, webviewSideReceiver, quickLoad }: Wi * Quick load is very fast, progress bar will flash and disappear. So we don't show it. */ const showProgressBar = loading && !quickLoad; - // TODO: check if webViewKeyToReloadAfterRecycleByOS on component is working. Sometimes the source works, but preload is not applied return ( <> @@ -135,10 +134,10 @@ export function WikiViewer({ wikiWorkspace, webviewSideReceiver, quickLoad }: Wi , servicesOfWorkspace: { - wikiHookService: WikiHookService; - wikiStorageService: WikiStorageService; -}) { +export function useStreamChunksToWebView( + webViewReference: MutableRefObject, + servicesOfWorkspace: MutableRefObject<{ wikiHookService: WikiHookService; wikiStorageService: WikiStorageService } | undefined>, +) { const [streamChunksToWebViewPercentage, setStreamChunksToWebViewPercentage] = useState(0); const sendDataToWebView = useCallback((messageType: OnStreamChunksToWebViewEventTypes, data?: string) => { console.log(`sendDataToWebView ${messageType}`); @@ -41,12 +41,12 @@ export function useStreamChunksToWebView(webViewReference: MutableRefObject { // start using `window.onStreamChunksToWebView` only when webviewLoaded, which means preload script is loaded. - if (webViewReference.current !== null) { + if (webViewReference.current !== null && servicesOfWorkspace.current !== undefined) { try { // Huawei HONOR device need to wait for a while before sending large data, otherwise first message (send HTML) will lost, cause white screen (no HTML loaded). Maybe its webview has bug. // Instead of `if (brand === 'HONOR') await new Promise(resolve => setTimeout(resolve, 1000));}`, we use heart beat to check if it is ready. // This is also required when app bring from background after a while, the webview will be recycled, and need to wait for it to resume before sending large data, otherwise first few data will be lost. - await servicesOfWorkspace.wikiHookService.waitForWebviewReceiverReady(() => { + await servicesOfWorkspace.current.wikiHookService.waitForWebviewReceiverReady(() => { sendDataToWebView(OnStreamChunksToWebViewEventTypes.CHECK_RECEIVER_READY); }); /** @@ -97,7 +97,7 @@ export function useStreamChunksToWebView(webViewReference: MutableRefObject, keyToTriggerReload: number, quickLoad: boolean, - servicesOfWorkspace: { - wikiHookService: WikiHookService; - wikiStorageService: WikiStorageService; - }, + servicesOfWorkspace: MutableRefObject<{ wikiHookService: WikiHookService; wikiStorageService: WikiStorageService } | undefined>, ) { const [loadHtmlError, setLoadHtmlError] = useState(''); const tiddlersStreamReference = useRef(); diff --git a/src/services/WikiHookService/hooks.ts b/src/services/WikiHookService/hooks.ts index 476ab36..1f314ba 100644 --- a/src/services/WikiHookService/hooks.ts +++ b/src/services/WikiHookService/hooks.ts @@ -3,6 +3,7 @@ import { useRegisterProxy } from 'react-native-postmessage-cat'; import { WebView } from 'react-native-webview'; import { IWikiWorkspace } from '../../store/workspace'; import { nativeService } from '../NativeService'; +import { WikiStorageService } from '../WikiStorageService'; import { WikiHookService } from '.'; import { WikiHookServiceIPCDescriptor } from './descriptor'; @@ -12,14 +13,17 @@ export function useWikiHookService(workspace: IWikiWorkspace) { return [webViewReference, onMessageReference, wikiHookService] as const; } -export function useSetWebViewReferenceToService(wikiHookService: WikiHookService, webViewReference: MutableRefObject) { +export function useSetWebViewReferenceToService( + servicesOfWorkspace: MutableRefObject<{ wikiHookService: WikiHookService; wikiStorageService: WikiStorageService } | undefined>, + webViewReference: MutableRefObject, +) { useEffect(() => { - if (wikiHookService !== undefined) { - wikiHookService.setLatestWebViewReference(webViewReference); - nativeService.setCurrentWikiHookServices(wikiHookService); + if (servicesOfWorkspace.current !== undefined) { + servicesOfWorkspace.current.wikiHookService.setLatestWebViewReference(webViewReference); + nativeService.setCurrentWikiHookServices(servicesOfWorkspace.current.wikiHookService); return () => { nativeService.clearCurrentWikiHookServices(); }; } - }, [webViewReference, wikiHookService]); + }, [webViewReference]); } diff --git a/src/services/registerServiceOnWebView.ts b/src/services/registerServiceOnWebView.ts index c1a7079..53f95b7 100644 --- a/src/services/registerServiceOnWebView.ts +++ b/src/services/registerServiceOnWebView.ts @@ -1,3 +1,4 @@ +import { useEffect, useRef } from 'react'; import { useMergedReference } from 'react-native-postmessage-cat'; import { IWikiWorkspace } from '../store/workspace'; import { AppDataServiceIPCDescriptor } from './AppDataService/descriptor'; @@ -58,10 +59,16 @@ export function useRegisterService(workspace: IWikiWorkspace) { /** * Services that are limited to the workspace. Can not be accessed globally. */ - const servicesOfWorkspace = { - wikiStorageService, - wikiHookService, - }; + const servicesOfWorkspace = useRef<{ + wikiHookService: typeof wikiHookService; + wikiStorageService: typeof wikiStorageService; + }>(); + useEffect(() => { + servicesOfWorkspace.current = { + wikiStorageService, + wikiHookService, + }; + }, [wikiStorageService, wikiHookService]); return [mergedWebViewReference, mergedOnMessageReference, registerServiceOnWebView, servicesOfWorkspace] as const; }