【问题标题】:React-Native: Go back on android hardware back button pressedReact-Native:按下 android 硬件后退按钮返回
【发布时间】:2017-01-19 15:23:21
【问题描述】:

我正在尝试在按下 android 后退按钮时添加返回 webview,但我仍然无法使其工作。

这是我的代码:

<WebView
    ref={WEBVIEW_REF}
    source={source}
    domStorageEnabled={true}
    onNavigationStateChange={this.onNavigationStateChange}
/>

componentDidMount() {
    BackAndroid.addEventListener('hardwareBackPress', function() {
        if(this.state.backButtonEnabled) {
            this.refs[WEBVIEW_REF].goBack();
            return true;
        }
    });
};

onNavigationStateChange = (navState) => {
    this.setState({
        backButtonEnabled: navState.canGoBack,
    });
};

使用上面的代码,我得到错误 undefined is not an object this.state.backButtonEnabled(在状态中设置)。

我只是想看看 goBack 是否有效,所以我删除了 if 语句,然后我得到错误 undefined is not an object this.refs[WEBVIEW_REF]。

什么是最好的解决方案?

【问题讨论】:

  • 如果在render方法中抛出backandroid事件监听器会怎样?
  • 我遇到了同样的错误。

标签: android reactjs webview react-native


【解决方案1】:

想添加一个完整的例子,以防它帮助任何人:

import React, { Component } from 'react';
import {
  BackHandler,
  Platform,
  WebView,
} from 'react-native';

class ExampleWebView extends Component {
  webView = {
    canGoBack: false,
    ref: null,
  }

  onAndroidBackPress = () => {
    if (this.webView.canGoBack && this.webView.ref) {
      this.webView.ref.goBack();
      return true;
    }
    return false;
  }

  componentWillMount() {
    if (Platform.OS === 'android') {
      BackHandler.addEventListener('hardwareBackPress', this.onAndroidBackPress);
    }
  }

  componentWillUnmount() {
    if (Platform.OS === 'android') {
      BackHandler.removeEventListener('hardwareBackPress');
    }
  }

  render() {
    return (
      <WebView
        source={{ uri: "https://www.google.com" }}
        ref={(webView) => { this.webView.ref = webView; }}
        onNavigationStateChange={(navState) => { this.webView.canGoBack = navState.canGoBack; }}
      />
    );
  }
}

【讨论】:

  • 这是一个全面的解决方案。也许你应该创建一个要点?
  • 出现错误 - TypeError: TypeError: undefined is not an object (evalating '_this2.webView.ref = webView')
  • 我想需要绑定onAndroidBackPress
  • @Crisfole 如果您使用箭头函数,就像我在此处的示例中使用的那样。
  • 我很确定还有一些额外的复杂性,尤其是在事件绑定方面。不过我可能是错的。 javascriptweblog.wordpress.com/2015/11/02/…
【解决方案2】:
class MyComponent extends Component {
    state = {};
    componentDidMount(){
         BackHandler.addEventListener('hardwareBackPress', this.backHandler);
    }
    componentWillUnmount(){
         BackHandler.removeEventListener('hardwareBackPress', this.backHandler);
    }
    backHandler = () => {
        if(this.state.backButtonEnabled) {
            this.refs[WEBVIEW_REF].goBack();
            return true;
        }
    }
}

1) 绑定你的处理程序 2) 不要忘记在卸载时删除监听器。

【讨论】:

  • 我确实在 5 分钟前修复了它,这实际上也是我所做的 :) 仍然感谢您的帮助,我肯定也会帮助其他开发人员!
  • BackAndroid 将被弃用,最好使用 BackHandler 像 @RamRovi 回答
【解决方案3】:

这是一个带有 Typescript 和 useRefuseEffect 钩子的解决方案。

我没有使用canGoBack,但它似乎无论如何都可以工作。

import React, { useEffect, useRef } from 'react';
import { BackHandler } from 'react-native';
import WebView from 'react-native-webview';

const WebViewWrapper = (): JSX.Element => {
  const webview = useRef<WebView>(null);
  const onAndroidBackPress = (): boolean => {
    if (webview.current) {
      webview.current.goBack();
      return true; // prevent default behavior (exit app)
    }
    return false;
  };
  useEffect((): (() => void) => {
    BackHandler.addEventListener('hardwareBackPress', onAndroidBackPress);
    return (): void => {
      BackHandler.removeEventListener('hardwareBackPress', onAndroidBackPress);
    };
  }, []); // Never re-run this effect
  return (
    <WebView
      source={{ uri: 'https://stackoverflow.com' }}
      ref={webview}
    />
  )
}

【讨论】:

  • 这条线帮助了我return true; // prevent default behavior (exit app)
【解决方案4】:

这可能对某人有所帮助,因为上述解决方案没有解决我的问题....

import React, { Component } from 'react';
import {
  BackHandler,
  WebView,
} from 'react-native';

export default class App extends Component {

constructor(props) {
    super(props);
    this.WEBVIEW_REF = React.createRef();
}

componentDidMount() {
    BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}

componentWillUnmount() {
  BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}

handleBackButton = ()=>{
   this.WEBVIEW_REF.current.goBack();
   return true;
}

onNavigationStateChange(navState) {
  this.setState({
    canGoBack: navState.canGoBack
  });
}

render(){
   return (
    <WebView
        source={{ uri: "https://www.cbt.ng" }}
        ref={this.WEBVIEW_REF}
        onNavigationStateChange={this.onNavigationStateChange.bind(this)}
     />
    )

 }
}

【讨论】:

    【解决方案5】:

    如果您正在寻找functional component 解决方案。

    注意:执行返回操作不需要canGoBack状态,它只是为了保存当前状态,你可以放心删除它

    import React, { useState, useEffect, useRef } from "react"
    import { BackHandler, Platform } from "react-native"
    import { SafeAreaView } from "react-navigation"
    import { WebView } from "react-native-webview"
    
    const Webview = () => {
      const webView = useRef(null);
      const [canGoBack, setCanGoBack] = useState(false);
    
      useEffect(() => {
        if (Platform.OS === 'android') {
          BackHandler.addEventListener('hardwareBackPress', HandleBackPressed);
    
          return () => {
            BackHandler.removeEventListener('hardwareBackPress', HandleBackPressed);
          }
        }
      }, []); // INITIALIZE ONLY ONCE
    
      const HandleBackPressed = () => {
        if (webView.current) {
          webView.current.goBack();
          return true; // PREVENT DEFAULT BEHAVIOUR (EXITING THE APP)
        }
        return false;
      }
    
      return (
        <SafeAreaView>
          <WebView
            ref={webView}
            source={{
              uri: "<YOUR_URL>"
            }}
            onNavigationStateChange={navState => setCanGoBack(navState.canGoBack)}
          />
        </SafeAreaView>
      )
    }
    
    export default Webview;
    

    【讨论】:

    • 请不要使用状态来维护canGoBack,因为改变状态会导致重新渲染,而是使用refs
    • 嘿,这是可行的,但是从应用程序中,我们无法在按下后退按钮时退出,就像在家里我们按下后退一样,所以它应该退出但它没有退出应用程序
    • 历史长度不小于2才会退出应用
    【解决方案6】:

    不幸的是,onNavigationStateChange 没有为 SPA(单页应用程序)网站触发:https://github.com/react-native-webview/react-native-webview/issues/1510

    改用onLoadProgress

    import React, { useRef, useState, useCallback, useEffect } from "react";
    import { BackHandler } from "react-native";
    import { WebView } from "react-native-webview";
    
    export default function App() {
      const webView = useRef();
    
      const [canGoBack, setCanGoBack] = useState(false);
    
      const handleBack = useCallback(() => {
        if (canGoBack && webView.current) {
          webView.current.goBack();
          return true;
        }
        return false;
      }, [canGoBack]);
    
      useEffect(() => {
        BackHandler.addEventListener("hardwareBackPress", handleBack);
        return () => {
          BackHandler.removeEventListener("hardwareBackPress", handleBack);
        };
      }, [handleBack]);
    
      return (
        <WebView
          ref={webView}
          source={{ uri: "https://my-awesome-spa.com/" }}
          onLoadProgress={(event) => setCanGoBack(event.nativeEvent.canGoBack)}
        />
      );
    }
    

    【讨论】:

    • 感谢您的回答。它对我有用......
    【解决方案7】:

    在 react native 中的 webview 的情况下,默认情况下按下移动端的后退按钮时应用程序退出。如果你想在按下返回按钮的时候回到上一页,那么你需要实现react-native webview的“返回”功能。

    您可以查看本文的Step 5 : Handle Mobile Back Button部分。

    【讨论】:

      【解决方案8】:

      添加到@Nisharg Shah 答案。对于onNavigationStateChange 道具,添加以下行

      onNavigationStateChange={navState => {webView.current.canGoBack = navState.canGoBack}}

      HandleBackPressed方法中检查webView.current.canGoBack然后webView.current.goBack();否则return false

      import React, { useState, useEffect, useRef } from "react"
      import { BackHandler, Platform } from "react-native"
      import { SafeAreaView } from "react-navigation"
      import { WebView } from "react-native-webview"
      
      const Webview = () => {
      const webView = useRef(null);
      const [canGoBack, setCanGoBack] = useState(false);
      
      useEffect(() => {
        if (Platform.OS === 'android') {
          BackHandler.addEventListener('hardwareBackPress', HandleBackPressed);
      
          return () => {
             BackHandler.removeEventListener('hardwareBackPress', HandleBackPressed);
          }
        }
      }, []); // INITIALIZE ONLY ONCE
      
      const HandleBackPressed = () => {
          if (webView.current.canGoBack) {
              webView.current.goBack();
              return true; // PREVENT DEFAULT BEHAVIOUR (EXITING THE APP)
          }
          return false;
      }
      
      return (
        <SafeAreaView>
          <WebView
            ref={webView}
            source={{
              uri: "<YOUR_URL>"
            }}
            onNavigationStateChange={navState => {webView.current.canGoBack = navState.canGoBack}} ->> This line is important
        />
       </SafeAreaView>
       )
      }
      
      export default Webview;
      

      【讨论】:

        【解决方案9】:

        所有功能组件的答案都有缺陷(比如当webview无法返回时无法使用返回按钮退出应用程序)。

        这与最受好评的基于类的答案的行为相同:

        import React, { useEffect, useRef, useState } from 'react';
        import { BackHandler, Platform } from 'react-native';
        import { WebView } from 'react-native-webview';
        
        const App = () => {
          const webview = useRef<WebView>(null);
          const [canGoBack, setCanGoBack] = useState(false);
        
          const onAndroidBackPress = () => {
            if (canGoBack && webview.current) {
              webview.current.goBack();
              return true;
            }
        
            return false;
          }
        
          useEffect(() => {
            if (Platform.OS === 'android') {
              BackHandler.addEventListener('hardwareBackPress', onAndroidBackPress);
            }
            return () => {
              BackHandler.removeEventListener('hardwareBackPress', onAndroidBackPress);
            }
          }, [canGoBack]);
        
          return (
            <WebView
              source={{uri: 'https://www.google.com'}}
              ref={webview}
              onNavigationStateChange={(navState) => setCanGoBack(navState.canGoBack)}
            />
          );
        };
        
        export default App;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-02
          • 2017-11-30
          • 1970-01-01
          • 2020-07-20
          • 2019-08-20
          相关资源
          最近更新 更多