问题描述
通知打开事件上的 Onesignal 在主屏幕启动后触发,然后导航到所需的屏幕。我想检测应用程序是否在主屏幕呈现之前按下通知启动,以便我可以直接导航到第二个屏幕并避免不必要地调用 api。
- "react-native-onesignal": "^3.9.3"
- “反应导航”:“^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);
}
},[]);
调试
解决方法
您的问题是如何导航或设置初始屏幕取决于打开的通知负载?
1) - 根据打开的通知负载设置 initial screen
。
根据 class Lifecycle useEffect
在组件输出渲染后运行,所以 useEffect
中的 listener 直到组件数量增加时才监听,这就是之前显示的登录主屏幕的原因登录 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
取决于打开的通知负载。
首先你需要知道
需要渲染导航器才能处理操作 如果您 尝试在不渲染导航器或在导航器之前进行导航 完成安装,如果不处理,它会抛出并使您的应用程序崩溃。所以 你需要添加一个额外的检查来决定在你的 应用挂载。
阅读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',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>
);
}