When using react native deep linking, I am struggling to use a uri with a 2nd path. There are examples in the documentation https://reactnavigation.org/docs/4.x/deep-linking
The issue I am having is blahh://account --android will link to the correct screen however, blahh://account/keys --android will not. This is the same if I add any path to the screens in the AccountStack
I am using react navigation version 4.
const AccountStack = createStackNavigator(
{
Account: {
screen: Account,
path: '',
navigationOptions: {
...accountNavigationOptions,
...Account.navigationOptions,
},
},
AccountLoginAndSecurity: {
screen: AccountLoginAndSecurity,
path: '',
navigationOptions: () => ({
...defaultNavigationOptions,
headerTransitionPreset: 'uikit',
}),
},
CreateAccount: {
screen: CreateAccount,
path: '',
navigationOptions: () => ({
...defaultNavigationOptions,
headerTransitionPreset: 'uikit',
}),
},
KeysList: {
screen: KeysList,
path: 'keys',
navigationOptions: () => ({
...defaultNavigationOptions,
headerTransitionPreset: 'uikit',
}),
},
AccountSwitch: createAnimatedSwitchNavigator(
{
AccountLoading: {
screen: AccountLoading,
path: '',
params: {
theme: 'orange',
navigateScreen: 'CreateAccountOrLogin',
},
},
CreateAccountOrLogin: CreateAccountOrLogin,
Continue: AccountMenu,
},
{
initialRouteName: 'AccountLoading',
transition: createSwitchTransition(),
}
),
},
{
defaultNavigationOptions: accountNavigationOptions,
}
);
export const TabNavigator = createBottomTabNavigator(
{
Explore: {
screen: ExploreStack,
path: '',
},
Bookings: {
screen: YourBookingsStack,
path: '',
},
Account: {
screen: AccountStack,
path: 'account',
},
},
{
defaultNavigationOptions: ({ navigation }) => ({
// eslint-disable-next-line react/display-name
tabBarIcon: ({ focused }): React.ReactNode => {
const { routeName } = navigation.state;
let iconName;
if (routeName === 'Explore') {
focused
? (iconName = require('assets/icons/bottom_tab_icons/explore_tab_icon.png'))
: (iconName = require('assets/icons/bottom_tab_icons/explore_tab_icon_unselected.png'));
} else if (routeName === 'Bookings') {
focused
? (iconName = require('assets/icons/bottom_tab_icons/bookings_tab_icon.png'))
: (iconName = require('assets/icons/bottom_tab_icons/bookings_tab_icon_unselected.png'));
} else if (routeName === 'Account') {
focused
? (iconName = require('assets/icons/bottom_tab_icons/account_tab_icon.png'))
: (iconName = require('assets/icons/bottom_tab_icons/account_tab_icon_unselected.png'));
}
return <Image source={iconName} />;
},
tabBarOptions: {
showLabel: false,
style: {
elevation: 3,
borderTopColor: 'transparent',
backgroundColor: '#fff',
height: 50,
},
},
}),
navigationOptions: () => ({
headerBackTitle: null,
headerTitleStyle: { color: 'orange' },
}),
}
);
I just looked at the codebase and Account links through to the account screen before going to the keys screen.
Account: {
screen: Account,
path: '',
navigationOptions: {
...accountNavigationOptions,
...Account.navigationOptions,
},
},
so the fix was to add an empty path to this in the accountstack then it worked fine when going to npx uri-scheme open blahh://account/keys --android
Related
I am using Wix's react-native-navigation and I want to use react-native-flash-message. In the official document https://www.npmjs.com/package/react-native-flash-message, they have given we can use globally as well as locally but in my code, I am not getting where should I use it.
following is my code.
this is my app.js
import { Navigation } from "react-native-navigation";
import { Provider } from "react-redux";
import registerScreens from './components/Screens'
import Icon from 'react-native-vector-icons/FontAwesome';
import configureStore from "./store/configureStore";
const store = configureStore();
registerScreens(Provider, store);
// Start a App
Navigation.events().registerAppLaunchedListener(() => {
Promise.all([
Icon.getImageSource("bars", 30, 'black'),
Icon.getImageSource("share-alt", 30, 'black')
]).then(sources => {
Navigation.setRoot({
root: {
sideMenu: {
left: {
component: {
name: 'app.NavigationDrawer',
passProps: {
text: 'This is a left side menu screen'
}
}
},
center: {
stack: {
id: 'mainStack',
children: [
{
stack: {
id: 'tab1Stack',
children: [
{
component: {
name: 'app.Component'
}
}
],
options: {
topBar: {
background: {
color: '#50A7C2',
},
title: {
text: 'Namaz Timing',
fontSize: 20,
//color: 'white',
fontFamily: 'Ubuntu',
alignment: 'left'
},
leftButtons: [
{
id: 'buttonOne',
icon: sources[0]
}
],
rightButtons: [
{
id: 'buttonTwo',
icon: sources[1]
}
]
}
}
}
},
],
options: {
topBar: {
background: {
color: '#50A7C2',
}
},
}
}
}
}
}
});
});
});
And this is my function where I want to use it
import qs from 'qs';
import { AsyncStorage } from 'react-native';
export async function addMasjid(Name, Address, email, Timing1, Timing2, Timing3, Timing4, Timing5, Timing6, Timing7) {
const Data = await AsyncStorage.getItem('tokenData');
parsed = JSON.parse(Data)
var token = parsed.access_token;
return fetch(`URL`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
},
body: qs.stringify({
'name': Name,
'address': Address,
'email': email,
'time_': Timing,
'time_': Timing,
'time_': Timing,
'time_': Timing,
'time_': Timing,
'time_': Timing,
'time_': Timing,
})
})
.then(res => res.json())
.catch(err => console.log(err))
Import the Flash Message component in your App.js and call it in the bottom.
App.js
import React from "react";
import { View } from "react-native";
import FlashMessage from "react-native-flash-message";
export default class App extends React.Component {
render() {
return (
<View style={{ flex: 1 }}>
// your entire code
<FlashMessage position="top" /> <--- at the bottom
</View>
);
}
}
Now, in your file where you wanna use it.
import { showMessage, hideMessage } from "react-native-flash-message";
Then, just use showMessage in the function you want to. Example:
const someFunc = () => {
showMessage({
message : 'some message',
type: 'success'
... other attributes
})
}
When I specify drawerLockMode direactly with createStackNavigator it is not working.
const drawerStack = createStackNavigator({
HomeScreen: { screen: HomeScreen },
}, {
headerMode: 'screen',
navigationOptions: {
drawerLockMode:'locked-closed'
}
})
But when I use drawerStack variable to define navigationOptions, it is working.
drawerStack.navigationOptions = ({ navigation }) => {
drawerLockMode = 'locked-closed';
return {
drawerLockMode,
};
};
Am I doing any mistake when I am directly using it inside createStackNavigator?
Update
As #bennygenel suggested, we need to user drawerLockMode in drawerNavigator instead of stackNavigator. Here is what i have done.
const drawerNavigator = createDrawerNavigator({
drawerStack: drawerStack
}, {
contentComponent: DrawerComponent,
navigationOpions:{
drawerLockMode:'locked-closed'
}
})
But it is not working in this way also. The only way it is working is by using the const variable created using createStackNavigator or createDrawerNavigator
Try the following code, it's working for me:
const UserHome_StackNavigator = StackNavigator({
userHm: {
screen: UserHome,
navigationOptions: ({ navigation }) => ({
title: 'User screen title',
headerStyle: {
backgroundColor: 'white',
},
headerTintColor: 'black'
}),
},
});
UserHome_StackNavigator.navigationOptions = ({ navigation }) => {
let drawerLockMode = 'locked-closed';
//logic here to change conditionaly, if needed
return {
drawerLockMode,
};
};
in case someone need this:
const drawerNavigator = createDrawerNavigator({
drawerStack: drawerStack
}, {
contentComponent: DrawerComponent,
navigationOpions: ({navigation}) => {
let routeName = navigation.state.routes[navigation.state.routes.length-1].routeName;
if(['Animation', 'Splash', 'Intro', 'Login', 'Signup'].indexOf(routeName)>=0){
return {
drawerLockMode: 'locked-closed'
}
}
return {}
}
})
Here is the error I get when navigating to that screen. Note that the error happens on Android only, not on iOS (despite being generally related to malformed JSX).
Cannot add a child that doesn't have a YogaNode to a parent without a measure function! (Trying to add a 'ReactRawTextShadowNode' to a 'LayoutShadowNode')
Basically, here is my main TabNavigator, using the ContactScreen component as a screen (repo link):
const CustomTabs = TabNavigator({
Campaigns: {
screen: Campaigns,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (<Icon name="mail" style={{ color: tintColor }} />)
}
},
Transactional: {
screen: MessagesList,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (<Icon name="stats" style={{ color: tintColor }} />)
}
},
Contacts: {
screen: ContactsScreen,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (<Icon name="contacts" style={{ color: tintColor }} />)
}
}
And here is the ContactsScreen component returning a StackNavigator, which is used as a screen inside the main TabNavigator (repo link):
const ListsNavigator = StackNavigator({
ContactLists: {
screen: ContactLists,
navigationOptions: {
header: 'none',
},
},
ContactList: {
screen: ContactList,
},
ListContacts: {
screen: ListContacts,
navigationOptions: ({ navigation }) => ({
title: `${navigation.state.params.name}`,
}),
},
},
{
initialRouteName: 'ContactLists'
}
)
export default class ContactsScreen extends React.Component {
render() {
return (
<ListsNavigator />
)
}
}
After investigating more, I found that the issue is due to a bug in react-navigation. More specifically, it's not possible to use a StackNavigator with the header field of navigationOptions set to 'none'. I filed an issue on the repo: https://github.com/react-navigation/react-navigation/issues/4081
I am using react-navigation in my react-native project and i want tab navigator in mid of my screen default it gives top or bottom position.
const Routes = {
RECENT: { screen : Upcomings},
UPNEXT : { screen : Upcomings},
UPCOMING :{ screen : Upcomings},
};
const TabConfig = {
stateName: 'MainNavigation',
tabBarOptions: {
activeTintColor: '#e91e63',
labelStyle: {
fontSize: 12,
},style: {
backgroundColor: '#ffffff',
borderTopWidth: 1,
borderTopColor: 'gray',
}
},
};
// register all screens of the app (including internal ones)
export const screenRoute = (SignIn) => {
return StackNavigator({
LOG_IN:{screen:Login},
SIGN_UP:{screen:SignUp},
CHARITY:{screen:Charity},
FETCH_FRIEND:{screen:FetchFriend},
DASHBOARD:{screen: Dashboard},
PAYPAL:{screen: Paypal},
FPASSWORD:{screen: ForgetPassword},
ADDFRIEND:{screen: AddFriend},
UPCOMINGS : {screen :TabNavigator(Routes, TabConfig)},
},{
headerMode: 'none',
mode:'modal',
initialRouteName: SignIn ? 'UPCOMINGS':'LOG_IN'
});
};
Could this been done by any way Thanks in advance.
I am following a tutorial for react-native, however they are doing it for IOS, there is one part where they use AlertIOS.prompt like this
AlertIOS.prompt(
'Add New Item',
null,
[
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{
text: 'Add',
onPress: (text) => {
this.itemsRef.push({ title: text })
}
},
],
'plain-text'
);
I am trying to remake this for android but cannot get it working, I did find this https://www.npmjs.com/package/react-native-prompt
import Prompt from 'react-native-prompt';
<Prompt
title="Say something"
placeholder="Start typing"
defaultValue="Hello"
visible={ this.state.promptVisible }
onCancel={ () => this.setState({
promptVisible: false,
message: "You cancelled"
}) }
onSubmit={ (value) => this.setState({
promptVisible: false,
message: `You said "${value}"`
}) }/>
However I cannot get this to work either, It is supposed to display the prompt when I press a button but nothing happens..
Here is the full original code with AlertIOS
'use strict';
import React, {Component} from 'react';
import ReactNative from 'react-native';
const firebase = require('firebase');
const StatusBar = require('./components/StatusBar');
const ActionButton = require('./components/ActionButton');
const ListItem = require('./components/ListItem');
const styles = require('./styles.js')
const {
AppRegistry,
ListView,
StyleSheet,
Text,
View,
TouchableHighlight,
AlertIOS,
} = ReactNative;
// Initialize Firebase
const firebaseConfig = {
apiKey: "AIzaSyA9y6Kv10CAl-QOnSkMehOyCUejwvKZ91E",
authDomain: "dontforget.firebaseapp.com",
databaseURL: "https://dontforget-bd066.firebaseio.com",
storageBucket: "dontforget-bd066.appspot.com",
};
const firebaseApp = firebase.initializeApp(firebaseConfig);
class dontforget extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
})
};
this.itemsRef = this.getRef().child('items');
}
getRef() {
return firebaseApp.database().ref();
}
listenForItems(itemsRef) {
itemsRef.on('value', (snap) => {
// get children as an array
var items = [];
snap.forEach((child) => {
items.push({
title: child.val().title,
_key: child.key
});
});
this.setState({
dataSource: this.state.dataSource.cloneWithRows(items)
});
});
}
componentDidMount() {
this.listenForItems(this.itemsRef);
}
render() {
return (
<View style={styles.container}>
<StatusBar title="Grocery List" />
<ListView
dataSource={this.state.dataSource}
renderRow={this._renderItem.bind(this)}
enableEmptySections={true}
style={styles.listview}/>
<ActionButton onPress={this._addItem.bind(this)} title="Add" />
</View>
)
}
_addItem() {
AlertIOS.prompt(
'Add New Item',
null,
[
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{
text: 'Add',
onPress: (text) => {
this.itemsRef.push({ title: text })
}
},
],
'plain-text'
);
}
_renderItem(item) {
const onPress = () => {
AlertIOS.alert(
'Complete',
null,
[
{text: 'Complete', onPress: (text) => this.itemsRef.child(item._key).remove()},
{text: 'Cancel', onPress: (text) => console.log('Cancelled')}
]
);
};
return (
<ListItem item={item} onPress={onPress} />
);
}
}
AppRegistry.registerComponent('dontforget', () => dontforget);
Could anyone tell me how I could make this work for android?
I think you can use the following libraries : https://github.com/mmazzarolo/react-native-dialog
Example code to get user input are as follows (not in docs)
<Dialog.Container visible={true}>
<Dialog.Title>Account delete</Dialog.Title>
<Dialog.Description>
Do you want to delete this account? You cannot undo this action.
</Dialog.Description>
<Dialog.Input label="Cancel" onChangeText={(text) => this.setState({username : text})} />
<Dialog.Button label="Delete" onPress={() => {
console.log(this.state.username);
this.setState({promptUser : false});
}} />
</Dialog.Container>
These looks like a good alternative since its natively implemented
https://github.com/shimohq/react-native-prompt-android
Actually, you can use a cross-platform prompt component that works fine both on Android and Ios. The link is given below.
https://www.npmjs.com/package/react-native-prompt-crossplatform and its
repository
link is
https://github.com/Ramiah-Viknesh/react-native-prompt-crossplatform
I developed a small utility to solve this issue. It might be useful.
https://github.com/eleviven/react-native-alertbox