尚未创建导航器时如何从链接导航(使用 branch.io 进行深度链接)?
How to navigate from linking (deep linking with branch.io) when navigator hasn't been created yet?
我非常关注 react-navigation deep linking 和 branch.io react-native 文档,要么两者都被弃用了,要么就是没有完全帮助。
我想要的是,每当深度 link 从 linking 读取时,导航到某个屏幕,我不想在特定屏幕上实现监听器,我想要这在根路径上,并且是 onReady(对我来说没用)或 linking from navigator container
这是我的代码,非常简单
const linking: LinkingOptions = {
prefixes: ['agendameio://', 'https://agendame.io', 'https://agendameio.app.link', 'https://agendameio.app-alternative.link'],
subscribe(listener) {
const navigation = useNavigation();
const onReceiveURL = ({ url }: { url: string }) => listener(url);
Linking.addEventListener('url', onReceiveURL);
branch.skipCachedEvents();
branch.subscribe(async ({ error, params, uri }) => {
if (error) {
console.error('Error from Branch: ' + error);
return;
}
if (params) {
DataManager.DynamicURL = params['~id'] === "951933826563912687" ? params.id : undefined;
}
let url = params?.['+url'] || params?.['~referring_link']; // params !== undefined ? `agendameio://empresa/${params.id}` : 'agendameio://empresa';
navigation.navigate(`DetalleEmpresa${params.id}`);
listener(url);
});
return () => {
Linking.removeEventListener('url', onReceiveURL);
branch.logout();
};
},
由于使用导航,我立即收到错误消息,但我真的不知道还能使用什么导航到应用程序内部
编辑:这是特别的错误
编辑 2:我将添加我的导航以帮助理解我的问题
function firstStack() {
return (
<homeStack.Navigator initialRouteName="EmpresasScreen">
<homeStack.Screen
options={({navigation}) => ({
headerShown: false,
headerTitle: () => (
<>
<View style={styles.viewHeader}>
<Image
resizeMode="contain"
style={styles.imageLogo}
source={Images.iconoToolbar}
/>
</View>
</>
),
})}
name="EmpresasScreen"
component={EmpresasScreen}
/>
<detalleEmpresaStack.Screen
options={{ headerShown: false }}
name="DetalleEmpresaScreen"
component={DetalleEmpresaScreen}
/>
<agendamientoStack.Screen
options={{ headerShown: false }}
name="AgendamientoScreen"
component={AgendamientoScreen}
/>
</homeStack.Navigator>
);
}
function secondStack() {
return (
<misCitasStack.Navigator>
<misCitasStack.Screen
options={({navigation}) => ({
headerShown: false,
headerTitle: () => (
<>
<View style={styles.viewHeader}>
<Image
resizeMode="contain"
style={styles.imageLogo}
source={Images.iconoToolbar}
/>
</View>
</>
),
})}
name="MisCitasScreen"
component={CitasScreen}
/>
<detalleCitasStack.Screen
options={({navigation}) => ({
headerShown: false,
})}
name="DetalleCitaScreen"
component={DetalleCitaScreen}
/>
</misCitasStack.Navigator>
);
}
function tabStack() {
return (
<tab.Navigator
screenOptions={({route}) => ({
tabBarIcon: ({focused}) => {
let iconName;
if (route.name === 'Home') {
iconName = focused
? Images.casaActive
: Images.casa
} else if (route.name === 'Citas') {
iconName = focused
? Images.citasActive
: Images.citas
}
return <Image source={iconName} />
}
})}
tabBarOptions={{
showLabel: false,
}}>
<tab.Screen name="Home" component={firstStack} />
<tab.Screen name="Citas" component={secondStack} />
</tab.Navigator>
);
}
function menuStackNavigator() {
useEffect(() => {
VersionCheck.needUpdate({forceUpdate: true}).then(async res => {
if (res.isNeeded) {
alertNeedUpdate(res.storeUrl, false);
}
});
if(Platform.OS === 'android') {
NativeModules.SplashScreenModule.hide();
}
}, [])
return (
<NavigationContainer linking={linking}>
<stack.Navigator headerMode="none">
<stack.Screen name="Home" component={tabStack} />
<stack.Screen name="Error" component={ErrorScreen} />
</stack.Navigator>
</NavigationContainer>
);
};
const styles = StyleSheet.create({
viewHeader: {
alignItems: 'center',
justifyContent: 'center',
},
imageLogo: {
alignItems: 'center',
justifyContent: 'center',
marginTop: 6,
marginBottom: 6
}
});
export default menuStackNavigator;
你能试试这样吗
const App = () => {
return (
<NavigationContainer>
<AppNavigator />
</NavigationContainer>
);
};
并在
中订阅
export const AppNavigator = () => {
const navigation =useNavigation();
useEffect(()=>{
//add listener and navigation logic here
},[]);
return (
<Stack.Navigator >
...
</Stack.Navigator>
);
};
这将使导航上下文在 AppNavigator 组件中可用
您可以使用配置链接直接打开目标屏幕。
在此处查看更多示例configuring-links
这里 URL /feed
将打开名为 Chat
.
的屏幕
import { NavigationContainer } from '@react-navigation/native';
const linking = {
prefixes: ['https://mychat.com', 'mychat://'],
config: {
screens: {
Chat: 'feed/:sort', //URL `/feed` will open screen named `Chat`.
Profile: 'user',
}
},
};
function App() {
return (
<NavigationContainer linking={linking} fallback={<Text>Loading...</Text>}>
<Stack.Navigator>
<Stack.Screen name="Chat" component={ChatScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
或使用navigationRef
.
了解它 navigating-without-navigation-prop。
等待导航准备就绪,然后导航。
import { createNavigationContainerRef } from '@react-navigation/native';
function App() {
const navigationRef = createNavigationContainerRef();
const navigateWhenNavigationReady = (routeName, params, n = 0) => {
setTimeout(() => {
if (navigationRef?.getRootState()) {
navigationRef.navigate(routeName, params)
}else if (n < 100) {
navigateWhenNavigationReady(routeName, params, n + 1);
}
}, 300)
}
const linking = {
...,
subscribe(listener) {
...
navigateWhenNavigationReady("Chat", {id: 123});
}
};
return (
<NavigationContainer ref={navigationRef} linking={linking}>
<Stack.Navigator>
<Stack.Screen name="Chat" component={ChatScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
回答使用自定义挂钩 useNavigationWhenReady
。
const useNavigationWhenReady = (isReady, navigationRef) => {
const [routeName, setRouteName] = React.useState();
const [routeParams, setRouteParams] = React.useState({});
const [navigationAction, setNavigationAction] = React.useState("navigate");
React.useEffect(() => {
if (isReady && routeName) {
if(navigationRef && navigationRef[navigationAction]) {
const _navigationAction = navigationRef[navigationAction];
_navigationAction(routeName, routeParams);
}
}
}, [isReady, routeParams, routeParams]);
const navigate = (_routeName, _routeParams = {}) => {
if(!routeName) {
setNavigationAction("navigate");
setRouteParams(_routeParams);
setRouteName(_routeName);
}
};
const reset = (state) => {
if(!routeName) {
setNavigationAction("reset");
setRouteName(state);
}
};
return { navigate, reset }
};
您现在可以使用 useNavigationWhenReady
而不是 useNavigation
;
import { createNavigationContainerRef } from '@react-navigation/native';
function App() {
const [isReady, setReady] = React.useState(false);
const navigationRef = createNavigationContainerRef();
//define it here
const navigation = useNavigationWhenReady(isReady, navigationRef);
const handleOpenNotificationOrOpenLinking = () => {
...
navigation.navigate("screenName", {param1: value1});
//or use reset
//navigation.reset({
//index: 1,
//routes: [{ name: 'screenName' }]
//});
};
return (
<NavigationContainer ref={navigationRef} onReady={() => setReady(true)}>
</NavigationContainer>
);
}
如果你使用 react-navigation-v5 而不是 v6 使用
//const navigationRef = createNavigationContainerRef();
//const navigation = useNavigationWhenReady(isReady, navigationRef);
const navigationRef = React.useRef();
const navigation = useNavigationWhenReady(isReady, navigationRef?.current);
您还可以在导航未就绪时显示加载或启动画面
return (
<NavigationContainer ref={navigationRef} onReady={() => setReady(true)}>
<RootStack.Navigator initialRouteName={isReady ? "home" : "loading"} >
</RootStack>
</NavigationContainer>
);
我非常关注 react-navigation deep linking 和 branch.io react-native 文档,要么两者都被弃用了,要么就是没有完全帮助。
我想要的是,每当深度 link 从 linking 读取时,导航到某个屏幕,我不想在特定屏幕上实现监听器,我想要这在根路径上,并且是 onReady(对我来说没用)或 linking from navigator container
这是我的代码,非常简单
const linking: LinkingOptions = {
prefixes: ['agendameio://', 'https://agendame.io', 'https://agendameio.app.link', 'https://agendameio.app-alternative.link'],
subscribe(listener) {
const navigation = useNavigation();
const onReceiveURL = ({ url }: { url: string }) => listener(url);
Linking.addEventListener('url', onReceiveURL);
branch.skipCachedEvents();
branch.subscribe(async ({ error, params, uri }) => {
if (error) {
console.error('Error from Branch: ' + error);
return;
}
if (params) {
DataManager.DynamicURL = params['~id'] === "951933826563912687" ? params.id : undefined;
}
let url = params?.['+url'] || params?.['~referring_link']; // params !== undefined ? `agendameio://empresa/${params.id}` : 'agendameio://empresa';
navigation.navigate(`DetalleEmpresa${params.id}`);
listener(url);
});
return () => {
Linking.removeEventListener('url', onReceiveURL);
branch.logout();
};
},
由于使用导航,我立即收到错误消息,但我真的不知道还能使用什么导航到应用程序内部
编辑:这是特别的错误
编辑 2:我将添加我的导航以帮助理解我的问题
function firstStack() {
return (
<homeStack.Navigator initialRouteName="EmpresasScreen">
<homeStack.Screen
options={({navigation}) => ({
headerShown: false,
headerTitle: () => (
<>
<View style={styles.viewHeader}>
<Image
resizeMode="contain"
style={styles.imageLogo}
source={Images.iconoToolbar}
/>
</View>
</>
),
})}
name="EmpresasScreen"
component={EmpresasScreen}
/>
<detalleEmpresaStack.Screen
options={{ headerShown: false }}
name="DetalleEmpresaScreen"
component={DetalleEmpresaScreen}
/>
<agendamientoStack.Screen
options={{ headerShown: false }}
name="AgendamientoScreen"
component={AgendamientoScreen}
/>
</homeStack.Navigator>
);
}
function secondStack() {
return (
<misCitasStack.Navigator>
<misCitasStack.Screen
options={({navigation}) => ({
headerShown: false,
headerTitle: () => (
<>
<View style={styles.viewHeader}>
<Image
resizeMode="contain"
style={styles.imageLogo}
source={Images.iconoToolbar}
/>
</View>
</>
),
})}
name="MisCitasScreen"
component={CitasScreen}
/>
<detalleCitasStack.Screen
options={({navigation}) => ({
headerShown: false,
})}
name="DetalleCitaScreen"
component={DetalleCitaScreen}
/>
</misCitasStack.Navigator>
);
}
function tabStack() {
return (
<tab.Navigator
screenOptions={({route}) => ({
tabBarIcon: ({focused}) => {
let iconName;
if (route.name === 'Home') {
iconName = focused
? Images.casaActive
: Images.casa
} else if (route.name === 'Citas') {
iconName = focused
? Images.citasActive
: Images.citas
}
return <Image source={iconName} />
}
})}
tabBarOptions={{
showLabel: false,
}}>
<tab.Screen name="Home" component={firstStack} />
<tab.Screen name="Citas" component={secondStack} />
</tab.Navigator>
);
}
function menuStackNavigator() {
useEffect(() => {
VersionCheck.needUpdate({forceUpdate: true}).then(async res => {
if (res.isNeeded) {
alertNeedUpdate(res.storeUrl, false);
}
});
if(Platform.OS === 'android') {
NativeModules.SplashScreenModule.hide();
}
}, [])
return (
<NavigationContainer linking={linking}>
<stack.Navigator headerMode="none">
<stack.Screen name="Home" component={tabStack} />
<stack.Screen name="Error" component={ErrorScreen} />
</stack.Navigator>
</NavigationContainer>
);
};
const styles = StyleSheet.create({
viewHeader: {
alignItems: 'center',
justifyContent: 'center',
},
imageLogo: {
alignItems: 'center',
justifyContent: 'center',
marginTop: 6,
marginBottom: 6
}
});
export default menuStackNavigator;
你能试试这样吗
const App = () => {
return (
<NavigationContainer>
<AppNavigator />
</NavigationContainer>
);
};
并在
中订阅export const AppNavigator = () => {
const navigation =useNavigation();
useEffect(()=>{
//add listener and navigation logic here
},[]);
return (
<Stack.Navigator >
...
</Stack.Navigator>
);
};
这将使导航上下文在 AppNavigator 组件中可用
您可以使用配置链接直接打开目标屏幕。
在此处查看更多示例configuring-links
这里 URL /feed
将打开名为 Chat
.
import { NavigationContainer } from '@react-navigation/native';
const linking = {
prefixes: ['https://mychat.com', 'mychat://'],
config: {
screens: {
Chat: 'feed/:sort', //URL `/feed` will open screen named `Chat`.
Profile: 'user',
}
},
};
function App() {
return (
<NavigationContainer linking={linking} fallback={<Text>Loading...</Text>}>
<Stack.Navigator>
<Stack.Screen name="Chat" component={ChatScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
或使用navigationRef
.
了解它 navigating-without-navigation-prop。
等待导航准备就绪,然后导航。
import { createNavigationContainerRef } from '@react-navigation/native';
function App() {
const navigationRef = createNavigationContainerRef();
const navigateWhenNavigationReady = (routeName, params, n = 0) => {
setTimeout(() => {
if (navigationRef?.getRootState()) {
navigationRef.navigate(routeName, params)
}else if (n < 100) {
navigateWhenNavigationReady(routeName, params, n + 1);
}
}, 300)
}
const linking = {
...,
subscribe(listener) {
...
navigateWhenNavigationReady("Chat", {id: 123});
}
};
return (
<NavigationContainer ref={navigationRef} linking={linking}>
<Stack.Navigator>
<Stack.Screen name="Chat" component={ChatScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
回答使用自定义挂钩 useNavigationWhenReady
。
const useNavigationWhenReady = (isReady, navigationRef) => {
const [routeName, setRouteName] = React.useState();
const [routeParams, setRouteParams] = React.useState({});
const [navigationAction, setNavigationAction] = React.useState("navigate");
React.useEffect(() => {
if (isReady && routeName) {
if(navigationRef && navigationRef[navigationAction]) {
const _navigationAction = navigationRef[navigationAction];
_navigationAction(routeName, routeParams);
}
}
}, [isReady, routeParams, routeParams]);
const navigate = (_routeName, _routeParams = {}) => {
if(!routeName) {
setNavigationAction("navigate");
setRouteParams(_routeParams);
setRouteName(_routeName);
}
};
const reset = (state) => {
if(!routeName) {
setNavigationAction("reset");
setRouteName(state);
}
};
return { navigate, reset }
};
您现在可以使用 useNavigationWhenReady
而不是 useNavigation
;
import { createNavigationContainerRef } from '@react-navigation/native';
function App() {
const [isReady, setReady] = React.useState(false);
const navigationRef = createNavigationContainerRef();
//define it here
const navigation = useNavigationWhenReady(isReady, navigationRef);
const handleOpenNotificationOrOpenLinking = () => {
...
navigation.navigate("screenName", {param1: value1});
//or use reset
//navigation.reset({
//index: 1,
//routes: [{ name: 'screenName' }]
//});
};
return (
<NavigationContainer ref={navigationRef} onReady={() => setReady(true)}>
</NavigationContainer>
);
}
如果你使用 react-navigation-v5 而不是 v6 使用
//const navigationRef = createNavigationContainerRef();
//const navigation = useNavigationWhenReady(isReady, navigationRef);
const navigationRef = React.useRef();
const navigation = useNavigationWhenReady(isReady, navigationRef?.current);
您还可以在导航未就绪时显示加载或启动画面
return (
<NavigationContainer ref={navigationRef} onReady={() => setReady(true)}>
<RootStack.Navigator initialRouteName={isReady ? "home" : "loading"} >
</RootStack>
</NavigationContainer>
);