首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RN OneSignal _open事件

RN OneSignal _open事件
EN

Stack Overflow用户
提问于 2021-07-14 13:38:25
回答 1查看 301关注 0票数 3

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

  • “反应-本机-一个信号”:"^3.9.3“
  • “反应-导航”:"^4.0.0“

代码语言:javascript
复制
   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);
      }
   }, []);

Debug

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-07-18 22:44:50

您的问题是如何根据打开的通知有效载荷来导航或设置初始屏幕?

1) -根据打开的通知有效载荷设置initial screen

根据类生命周期 useEffect,在呈现组件输出之后运行,所以useEffect中的侦听器直到组件数量达到为止才会侦听,这是主屏幕中日志显示在useEffect日志之前的原因,请参见以下解释。

代码语言:javascript
复制
//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>;
}

你的代码可能是这样的。

代码语言:javascript
复制
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取决于打开的通知有效载荷。

首先你要知道

如果您试图在不呈现导航器的情况下导航,或者在导航器完成安装之前,它将抛出并使您的应用程序崩溃(如果不处理),则需要呈现导航器以处理操作。因此,您需要添加一个额外的检查,以决定做什么,直到您的应用程序挂载。

读取文档

代码语言:javascript
复制
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>
    );

}

setTimeoutCommonActions参考文献。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68379185

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档