I built my navigation based on Ex-navigation's example
Everything is working as expected, but I don't know how to Sign out
I have a <Main/> component which renders a <DrawerNavigationMenu/> as in the example
.This is my <DrawerNavigationMenu/>
render() {
return (
<DrawerNavigation
renderHeader={this._renderHeader}
drawerWidth={300}
initialItem="home">
<DrawerNavigationItem
id="home"
selectedStyle={styles.selectedItemStyle}
renderTitle={isSelected => this._renderTitle('Home', isSelected)}
renderIcon={isSelected => this._renderIcon('md-home', isSelected)}>
<StackNavigation
id="home"
defaultRouteConfig={{
navigationBar: {
backgroundColor: '#2497b7',
tintColor: '#fff',
height: 60,
},
}}
initialRoute={Router.getRoute('home')}/>
</DrawerNavigationItem>
<DrawerNavigationItem
id="logout"
selectedStyle={styles.selectedItemStyle}
renderTitle={isSelected => this._renderTitle('Logout', isSelected)}
renderIcon={isSelected => this._renderIcon('md-exit', isSelected)}>
<StackNavigation
id="root"
initialRoute={Router.getRoute('root')}/>
</DrawerNavigationItem>
</DrawerNavigation>
);
}
In the "logout" item I need to reset the navigation stack and render my Root scene without the chance of going back
I tried using initialStack= instead of initialRoute=, like this
<StackNavigation
id="root"
initialStack={[Router.getRoute('root')]}/>
But when I hit (Android)back, it still going back to Home scene. I'm not using Redux explicitly here. Is this the right way to implement a sign out navigation? Any ideas? Please!
Give DrawernavigationItem props onPress and call a function that switches between Authentication and Landing pages.
<DrawerNavigationItem
id="Sign out"
selectedStyle={styles.selectedItemStyle}
onPress={()=>{this.signOut()}}
renderTitle={isSelected => this._renderTitle('Sign out', isSelected)}
/>
Related
I have a root screen called selectlanguage once user select his language I'm passing that selected language as params to the Home screen, and then to "Home" children. but once I hit back button from that child screen to the Home that param turns to undefined that why when I want to open that child screen again it cause some issues.
Root screen selectedLanguage:
<View style={{ marginTop: 40 }}>
<Button
handleClick={() =>
navigation.navigate('Home', { lan: userLanData.value })
}
title={'NEXT'}
{...}
/>
Home screen:
const lan = route.params?.lan;
// and below i'm passing above param as props to Task screen
<Tasks
lanParam={lan}
{...}
/>
Task screen:
//Again passing it to another Child screen
<TouchableOpacity
onPress={() =>
navigation.navigate('byWords', {
id: item.id,
currentLevelName,
index,
lanParam, <-----
})
}>
{...}
</TouchableOpacity>
Task Child screen:
const lanParam = route?.params?.lanParam;
const colRef = collection(
db,
`${lanParam && lanParam}/${currLevelParam}/tasks/${id}/byWords/`
);
And from this point I had an idea to try send this Param back to home screen while coming back like this:
<Header
{...}
goBack={() =>
navigation.navigate('Home', { index, currLevelParam, lanParam })
}
/>
And now Home screen should look like this and I'm receiving that value back again:
Home screen:
const lan = route.params?.lan;
const lanParam = route.params?.lanParam;
// and below i'm passing above param as props to Task screen
<Tasks
lanParam={lan}
{...}
/>
But the problem is that, how could I use that value again since we have no access to the root screen again ?
it was easy to fix!!
I just modified lanParams to lan to keep same as Original param and update Home param again while coming back
I'm building a react-native application that displays Service overlay (like those facebook messenger bubble heads), implement in Android only, and on the overlay click it should go back to the app in a specific screen.
I'm using react-router-native and I have my routes structured like this:
App.js
<NativeRouter>
<ApolloProvider client={client}>
<Main>
<Switch>
<Route exact path="/home" component={Home} />
<Route exact path="/progress" component={RouteProgress} />
<Route exact path="/search" component={Search} />
</Switch>
</Main>
</ApolloProvider>
</NativeRouter>
The Main component has these:
Main.js
componentDidMount() {
console.log(this.props.location.pathname);
if(this.props.location.pathname === '/') {
this.props.history.push("/home");
}
}
The callback from my Native module is being called like this:
FloatingView.java
case MotionEvent.ACTION_UP:
if (lastAction == MotionEvent.ACTION_DOWN || delta < 3) {
Intent intent = new Intent(FloatingWindow.this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
FloatingViewPackage.callback.invoke();
stopSelf();
}
The callback is defined in the component Search, which also executes the native module:
Search.js
<Button onPress={() => FloatingView.init(() => {
console.log('go to progress 1');
this.props.history.push("/progress");
setTimeout(() => {
console.log('go to progress 2');
this.props.history.push("/progress");
}, 1000);
})}
The problem is that this.props.history.push("/progress"); doesn't work neither outside the timeout nor inside.
Outside the timeout, the function is called before Main componentDidMount but location.pathname is not updated. Inside it the function is called after, but it doesn't navigate to the right screen. It always fall into /home.
I thought this my be a life cycle issue, since the Search component is not mounted. I've been trying to figure a way out to make this work. I tried using the Redirect component:
<Button onPress={() => FloatingView.init(() => <Redirect to="/progress" />)}
Does anyway can think of a way around this? Thanks
Found a solution, don't know if the best one, but it works.
Created a singleton navigation.js
navigation.js
export default {
entryPoint: '/home'
};
And changed the following files:
Search.js
<Button onPress={() => FloatingView.init(() => {
navigation.entryPoint = "/progress";
})}
Main.js
componentDidMount() {
if(this.props.location.pathname === '/') {
this.props.history.push(navigation.entryPoint);
}
}
This is my JSON file
{
"name": "Thịt bò",
"noed": 5
},
{
"name": "Thịt heo",
"noed": 3
}
I get them to Flatlist
<FlatList
data={cats}
keyExtractor={item => item.name}
renderItem={({item})=>(
<View>
<Text style={styles.catsItem} onPress={() => this.changeTextInput(item.name)}>{item.name} {item.noed}</Text>
</View>
)}
/>
But I want to send 2 values are item.name and item.noed to TextInput then send them to another screen
changeTextInput(item){
this.setState({name: item});
};
But I don't know how to send item.noed to TextInput and how to send them to another screen.
I'm quite new, so please help me.
Use react-navigation npm package to redirect from one screen to another screen you can also pass values
There are two pieces to this:
Pass params to a route by putting them in an object as a second parameter to the navigation.navigate function:
this.props.navigation.navigate
('RouteName', { /* params go here */ })
onPress={()=>this.props.navigation.navigate('Details',
{ itemId: 86, otherParam: 'anything you want here', })};
Read the params in your screen component:
this.props.navigation.getParam(paramName, defaultValue)
For more information please read the following document
React Navigation Link
I'd like to have a context menu triggered on long press different places using React Native.
I.e. in a dialer like the default dailer. You can long-click on any contact and get a 'copy number' menu. And also you can long-click on the name of the person once you've opened their 'contact card'.
The straight-forward way needs a lot of copy-pasted boilerplate, both components and handlers.
Is there a better pattern for doing this?
All Touchable components (TouchableWithoutFeedback, TouchableOpacity etc.) has a property called onLongPress. You can use this prop to listen for long presses and then show the context menu.
To eliminate code mess and doing lots of copy paste you can separate your context menu as a different component and call it when the long press happen. You can also use an ActionSheet library to show the desired options. React native has a native API for iOS called ActionSheetIOS. If you get a little bit more experience in react and react-native you can create a better logic for this but I'm going to try to give you an example below.
// file/that/contains/globally/used/functions.js
const openContextMenu = (event, user, callback) => {
ActionSheetIOS.showActionSheetWithOptions({
options: ['Copy Username', 'Call User', 'Add to favorites', 'Cancel'],
cancelButtonIndex: [3],
title: 'Hey',
message : 'What do you want to do now?'
}, (buttonIndexThatSelected) => {
// Do something with result
if(callback && typeof callback === 'function') callback();
});
};
export openContextMenu;
import { openContextMenu } from './file/that/contains/globally/used/functions';
export default class UserCard extends React.Component {
render() {
const { userObject } = this.props;
return(
<TouchableWithoutFeedback onLongPress={(event) => openContextMenu(event, userObject, () => console.log('Done')}>
<TouchableWithoutFeedback onLongPress={(event) => openContextMenu(event, userObject, () => console.log('Done'))}>
<Text>{userObject.name}</Text>
<Image source={{uri: userObject.profilePic }} />
</TouchableWithoutFeedback>
</TouchableWithoutFeedback>
);
}
}
Similarly as the previous answer combine onLongPress with imperative control for popup menu - something like
<TouchableWithoutFeedback onLongPress={()=>this.menu.open()}>
<View style={styles.card}>
<Text>My first contact name</Text>
<Menu ref={c => (this.menu = c)}>
<MenuTrigger text="..." />
<MenuOptions>
// ...
</MenuOptions>
</Menu>
</View>
</TouchableWithoutFeedback>
When it comes to a lot of boilerplate - in React you can do your own components that you can reuse everywhere thus reducing boilerplate (and copy&paste)
See full example on https://snack.expo.io/rJ5LBM-TZ
Pretty simple question.. does anyone have a solution for detecting what component is open in React Native? Treating a page like a component?
My solution right now is to use a global state manager like Redux or Mobx and just constantly update it with whatever component you have open.
In you're renderScene property of your Navigator, you have access to the route object. So you can pass that down into whatever component you need.
<Navigator
configureScene={() => Navigator.SceneConfigs.FadeAndroid}
style={styles.navigator}
initialRoute={{ title: 'Welcome' }}
renderScene={(route, navigator) => {
if (route.title === Welcome) {
return <Welcome navigator={navigator} route={route} />
// Now inside Welcome, if you do this.props.route.title
// you can access the current route name 'Welcome'
}
}}
/>