I pretty much followed both react-navigation deep linking and branch.io react-native documentation, and either both are deprecated or just not pletely helpful.
All I want is that whenever a deep link reads from the linking, navigate to a certain screen, I'm not looking to implement a listener on a specific screen, I want this on a root path, and is either the onReady (which for me didn't work) or linking from navigator container
this is my code, very simple
const linking: LinkingOptions = {
prefixes: ['agendameio://', '', '', ''],
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();
};
},
I instantly get an error due to use navigation, but I really don't know what else to use to navigate to inside the app
EDIT: this is the error in particular
EDIT 2: I'll add my navigation so it can help to understand my problem
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"
ponent={EmpresasScreen}
/>
<detalleEmpresaStack.Screen
options={{ headerShown: false }}
name="DetalleEmpresaScreen"
ponent={DetalleEmpresaScreen}
/>
<agendamientoStack.Screen
options={{ headerShown: false }}
name="AgendamientoScreen"
ponent={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"
ponent={CitasScreen}
/>
<detalleCitasStack.Screen
options={({navigation}) => ({
headerShown: false,
})}
name="DetalleCitaScreen"
ponent={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" ponent={firstStack} />
<tab.Screen name="Citas" ponent={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" ponent={tabStack} />
<stack.Screen name="Error" ponent={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;
I pretty much followed both react-navigation deep linking and branch.io react-native documentation, and either both are deprecated or just not pletely helpful.
All I want is that whenever a deep link reads from the linking, navigate to a certain screen, I'm not looking to implement a listener on a specific screen, I want this on a root path, and is either the onReady (which for me didn't work) or linking from navigator container
this is my code, very simple
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();
};
},
I instantly get an error due to use navigation, but I really don't know what else to use to navigate to inside the app
EDIT: this is the error in particular
EDIT 2: I'll add my navigation so it can help to understand my problem
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"
ponent={EmpresasScreen}
/>
<detalleEmpresaStack.Screen
options={{ headerShown: false }}
name="DetalleEmpresaScreen"
ponent={DetalleEmpresaScreen}
/>
<agendamientoStack.Screen
options={{ headerShown: false }}
name="AgendamientoScreen"
ponent={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"
ponent={CitasScreen}
/>
<detalleCitasStack.Screen
options={({navigation}) => ({
headerShown: false,
})}
name="DetalleCitaScreen"
ponent={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" ponent={firstStack} />
<tab.Screen name="Citas" ponent={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" ponent={tabStack} />
<stack.Screen name="Error" ponent={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;
Share
Improve this question
edited Sep 1, 2021 at 18:58
Nicolas Silva
asked Aug 27, 2021 at 21:26
Nicolas SilvaNicolas Silva
6492 gold badges11 silver badges31 bronze badges
2
-
We don't yet have support for
react-navigation
. Can you share the error message you're observing here? – Kartik Shandilya Commented Aug 30, 2021 at 7:16 - @KartikShandilya my bad, post edited to include an image of the error, btw I want to clarify two things, both branch.io and react-navigation mention each other, and I quote react-navigation "Next, you would need to subscribe to ining links from your third-party integration, For example, to get to subscribe to ining links from branch.io:" and here from branch documentation, "Now push the view for this URL this.navigator.push({ title: title, url: url, image: image })" – Nicolas Silva Commented Aug 30, 2021 at 16:27
3 Answers
Reset to default 5 +50you can use Configuring links to open the target screen directly.
see more example here configuring-links
Here the URL /feed
will open screen named Chat
.
import { NavigationContainer } from '@react-navigation/native';
const linking = {
prefixes: ['https://mychat.', '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" ponent={ChatScreen} />
<Stack.Screen name="Profile" ponent={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
or use navigationRef
.
read about it navigating-without-navigation-prop.
wait to navigation to be ready and then navigate.
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" ponent={ChatScreen} />
<Stack.Screen name="Profile" ponent={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
can you try doing it like this
const App = () => {
return (
<NavigationContainer>
<AppNavigator />
</NavigationContainer>
);
};
and do the subscribe in
export const AppNavigator = () => {
const navigation =useNavigation();
useEffect(()=>{
//add listener and navigation logic here
},[]);
return (
<Stack.Navigator >
...
</Stack.Navigator>
);
};
this will make navigation context to be available in AppNavigator Component
Answer use custom hook 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 }
};
you can now use useNavigationWhenReady
instead of 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>
);
}
if you use react-navigation-v5 not v6 use
//const navigationRef = createNavigationContainerRef();
//const navigation = useNavigationWhenReady(isReady, navigationRef);
const navigationRef = React.useRef();
const navigation = useNavigationWhenReady(isReady, navigationRef?.current);
you can also show loading or splash screen while navigation not ready
return (
<NavigationContainer ref={navigationRef} onReady={() => setReady(true)}>
<RootStack.Navigator initialRouteName={isReady ? "home" : "loading"} >
</RootStack>
</NavigationContainer>
);