react-native - RN OneSignal _open 事件

标签 react-native push-notification react-navigation react-native-onesignal

主屏幕启动后,通知打开事件上的 OneSignal 会触发,然后导航到所需的屏幕。我想检测应用程序是否在主屏幕呈现之前按下通知启动,以便我可以直接导航到第二个屏幕并避免不必要地调用 api。

  • "react-native-onesignal": "^3.9.3"
  • "react-navigation": "^4.0.0"

代码
   const _opened = openResult => {
      const { additionalData, body } = openResult.notification.payload;
     // how to navigate or set the initial screen depending on the payload
   }

    useEffect(() => {

        onesignal.init();
        onesignal.addEventListener('received', _received);
        onesignal.addEventListener('opened', _opened);
        SplashScreen.hide();

      return () => {
        // unsubscriber
        onesignal.removeEventListener('received', _received);
        onesignal.removeEventListener('opened', _opened);
      }
   }, []);
调试
enter image description here

最佳答案

您的问题是如何根据打开的通知负载导航或设置初始屏幕?
1) - 设置 initial screen取决于打开的通知负载。
根据 class Lifecycle useEffect在组件输出渲染后运行,所以监听器在 useEffect直到组件数量增加才监听,这就是登录前显示的登录主屏幕的原因useEffect ,请参阅此说明。

//this the problem (NavigationContainer called before useEffect).
function App() {
  useEffect(() => {}); //called second.
  return <NavigationContainer>; //called first.
}

//this the solution (useEffect called Before NavigationContainer).
function App() {
  const [ready, setReady] = useState(false);

  //called second.
  useEffect(() => { 
    //listen here
    setReady(true);
    SplashScreen.hide();
  });

  //called first
  //no function or apis run before useEffect here it just view.
  if(!ready) return <></>;// or <LoadingView/>

   //called third.
  return <NavigationContainer>;
}
你的代码可能是这样的。
function App() {
    const [ready, setReady] = useState(false);

    const openedNotificationRef = useRef(null);
    
    const _opened = openResult => {
        openedNotificationRef.current = openResult.notification.payload;
    }

    const getInitialRouteName = () => {
        if (openedNotificationRef.current) {
            return "second"; //or what you want depending on the notification.
        }
        return "home";
    }


    useEffect(() => {
        onesignal.addEventListener('opened', _opened);
        //setTimeout(fn, 0) mean function cannot run until the stack on the main thread is empty.
        //this ensure _opened is executed if app is opened from notification
        setTimeout(() => {
            setReady(true);
        }, 0)
    });


    if(!ready) return <LoadingView/>


    return (
        <NavigationContainer initialRouteName={getInitialRouteName()}>
        </NavigationContainer>
    );

}
2) - navigate取决于打开的通知负载。
首先你需要知道

A navigator needs to be rendered to be able to handle actions If you try to navigate without rendering a navigator or before the navigator finishes mounting, it will throw and crash your app if not handled. So you'll need to add an additional check to decide what to do until your app mounts.


阅读 docs

function App() {

    const navigationRef = React.useRef(null);
    
    const openedNotificationRef = useRef(null);
    
    const _opened = openResult => {
        openedNotificationRef.current = openResult.notification.payload;
        //remove loading screen and start with what you want.
        const routes = [
            {name : 'home'}, //recommended add this to handle navigation go back
            {name : 'orders'}, //recommended add this to handle navigation go back
            {name : 'order', params : {id : payload.id}},
        ]
        navigationRef.current.dispatch(
            CommonActions.reset({
                routes : routes,
                index: routes.length - 1,
            })
        )
    }

    useEffect(() => {
        //don't subscribe to `opened` here
        
        //unsubscribe
        return () => {
            onesignal.removeEventListener('opened', _opened);
        }
    }, []);

    //subscribe to `opened` after navigation is ready to can use navigate
    const onReady = () => {
        onesignal.addEventListener('opened', _opened);
        //setTimeout(fn, 0) mean function cannot run until the stack on the main thread is empty.
        //this ensure _opened is executed if app is opened from notification
        setTimeout(() => {
            if (!openedNotificationRef.current) {
                //remove loading screen and start with home 
                navigationRef.current.dispatch(
                    CommonActions.reset({
                        routes : [{name : 'home'}],
                        index: 0,
                    })
                )
            }
        }, 0)
    };


    return (
        <NavigationContainer
            ref={navigationRef}
            onReady={onReady}
            initialRouteName={"justLoadingScreen"}>
        </NavigationContainer>
    );

}

引用 setTimeout , CommonActions .

关于react-native - RN OneSignal _open 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68379185/

相关文章:

android - React Native 中的 facebook.react.uimanager.ViewGroupDrawingOrderHelper.getChildDrawingOrder 中的 java.lang.ArrayIndexOutOfBoundsException

javascript - React native - 如何实现两个值之间的切换并根据所选值显示不同的 View

android - GCM 推送通知不通过代理

android - React Native Firebase : no custom sound, 无振动

android - React Navigation + Redux 在按下返回时关闭应用程序

amazon-web-services - 在 react native 和 expo 上使用 aws 放大数据存储获取错误 "Node is not supported"

grails - Grails 3应用程序-使用Turo的pushy插件的Apple Push通知

reactjs - react native / react 导航 : how do I access a component's state from `static navigationOptions` ?

android - 如何将 LinearGradient 用于 react 选项卡导航器选项卡

react 原生 Material 顶部选项卡导航器滑动禁用取决于屏幕