I have 2 classes: my default class HomeScreen used for the home page and another class MyList which I use to generate a flatlist on my HomeScreen.
My problem is that I do not succeed in building my navigation function in my MyList class.
I always get the following error: "Can't find variable: navigate".
I took a look at this Calling Navigate on Top Level Component but I really don't know how to implement it in my code.
Here's what I've tried:
class MyList extends React.Component {
_keyExtractor = (item, index) => item.note.id;
_renderItem = ({ item }) => (
<TouchableNativeFeedback
onPress={() => navigate('Note', { noteId: item.note.id })} >
<View>
<Text style={styles.noteElementTitle} >{item.note.title}</Text>
<Text style={styles.noteElementBody} >{item.note.body}</Text>
</View>
</TouchableNativeFeedback>
);
render() {
return (
<FlatList
data={this.props.data}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
);
}
}
export default class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Notes',
headerStyle: { backgroundColor: 'rgb(255, 187, 0)' },
headerTitleStyle: { color: 'white' },
};
render() {
const { navigate } = this.props.navigation;
return (
<MyList
data={this.state.data}
load={this.state.load}
navig={this.props.navigation}
>
</MyList>
);
}
}
const Project = StackNavigator({
Home: { screen: HomeScreen },
NewNote: { screen: NewNoteScreen },
Note: { screen: NoteScreen }
});
AppRegistry.registerComponent('Project', () => Project);
Thanks for your help.
Because your MyList component is not part of your stack the navigation prop is not available for that.
You have 2 options.
First option you can pass the navigation prop manually to MyList
render() {
const { navigate } = this.props.navigation;
return (
<MyList
data={this.state.data}
load={this.state.load}
navigation={this.props.navigation}
>
</MyList>
);
}
Second option you can use withNavigation.
withNavigation is a Higher Order Component which passes the navigation
prop into a wrapped Component. It's useful when you cannot pass the
navigation prop into the component directly, or don't want to pass it
in case of a deeply nested child.
import { Button } 'react-native';
import { withNavigation } from 'react-navigation';
const MyComponent = ({ to, navigation }) => (
<Button title={`navigate to ${to}`} onPress={() => navigation.navigate(to)} />
);
const MyComponentWithNavigation = withNavigation(MyComponent);
Related
React Native Expo App:
In render of my default class I map from an array that calls an arrow function outside of the class to return a line of text for each object. I would like to pass the navigation prop through so that on press of that text will navigate to another screen.
My navigation is set up correct as it is called from a touchable opacity elsewhere in render to navigate to another screen.
I have stripped this back quite a bit but hopefully enough to explain:
const CustomDialogContent = ({name, ip, navigate}) => {
return (
<Text onPress={navigate('Webview')}>
{name} ({ip})
</Text>
)
}
export default class HomeScreen extends React.Component {
constructor(props) {
super(props);
this.state ={
devices: [],
name: '',
ip: '',
};
}
static navigationOptions = {
title: 'App',
};
render() {
const {navigate} = this.props.navigation;
return (
<View style={container}>
<Dialog
<DialogContent>
{this.state.devices.map((device) => {
return (
<CustomDialogContent name={device.name} ip={device.ip} navigation={navigate}/>
);}
</DialogContent>
</Dialog>
</View>
);
}
}
Instead of taking me to the screen I get navigate is undefined. I have also tried this which threw undefined is not an object:
const CustomDialogContent = ({name, ip}) => {
const {navigate} = this.props.navigation;
return (
<Text onPress={navigate('Webview')}>
{name} ({ip})
</Text>
)
}
I then tried this which returned navigate is not a function:
const CustomDialogContent = ({name, ip, navigate}) => {
return (
<Text onPress={() => {navigate('Webview')}}>
{name} ({ip})
</Text>
)
}
Apologies if I am missing something quite basic I am a junior and completely new to react
Final solution with credit to #LonelyCpp:
const CustomDialogContent = props => {
return (
<Text onPress={() => {props.navigation('Webview');}}>
{props.name} ({props.ip})
</Text>
);
};
<CustomDialogContent name={device.name} ip={device.ip} navigation={navigate}/>
props are like variable assignments. You've done navigation={navigate} which means in CustomDialogContent gets the function as props.navigation
this should work -
const CustomDialogContent = (props) => {
const navigate = props.navigation; // no {}
return (
<Text onPress={()=>navigate('Webview')}>
{name} ({ip})
</Text>
)
}
edit : removed this since its a functional component
I'm working with React Native and React Navigation.
I have a component called App.js in which I declare the Drawer Navigation of React-Navigation.
In this I have an option to log out but I can not navigate to another component after removing the AsyncStorage
Does anyone know how to achieve it?
Thank you.
This is my code:
App.js
import { createDrawerNavigator, DrawerItems, NavigationActions } from 'react-navigation';
const customDrawerComponent = (props) => (
<SafeAreaView style={{ flex: 1 }}>
<ScrollView>
<DrawerItems
{...props}
/>
<TouchableOpacity style={styles.button} onPress={this.logOut} >
<Text> Logout </Text>
</TouchableOpacity>
</ScrollView>
</SafeAreaView>
);
logOut = () => {
// NOT WORKS
// this.props.navigation.navigate('Login')
//NOT WORKS:
this.myAction();
}
myAction = () => {
const nav = NavigationActions.navigate({
routeName: 'App',
});
return nav;
};
const AppDrawNavigator = createDrawerNavigator(
{
MainComponent: { screen: MainComponent,
navigationOptions: ({navigation}) => ({
drawerLockMode: 'locked-closed'
}) },
Login: { screen: LoginComponent,
navigationOptions: ({navigation}) => ({
drawerLockMode: 'locked-closed'
}) },
User: { screen: UsersComponent }
},
{
contentComponent: customDrawerComponent,
}
);
make this as a class like
export default class App extends React.Component {
constructor(props) {
super(props)
this.state = {
}
}
From your question I understand that either you want to :-
navigate from outside the components
navigate from components which do not have navigation prop.
For this I have tried 2 solutions and both work extremely fine though I based towards the second one.
First Solution
Use withNavigation from react-navigation package. If your components are deeply nested they wont have navigation prop unless u specify them manually or put them in context ;passing navigation prop becomes a real pain. So instead use withNavigation and your component would have navigation prop.
import {withNavigation} from "react-navigation";
const Component = ({navigation}) => {
const onPress = () => {
navigation.navigate(//ROUTE_NAME//)
}
return (
<TouchableOpacity onPress={onPress}>
<Text>Navigate</Text>
</TouchableOpacity>
)
}
export default withNavigation(Component);
Second Solution
Create a helper script and use that.
"use strict";
import React from "react";
import {NavigationActions} from "react-navigation";
let _container; // eslint-disable-line
export const navigation = {
mapProps: (SomeComponent) => {
return class extends React.Component {
static navigationOptions = SomeComponent.navigationOptions; // better use hoist-non-react-statics
render () {
const {navigation: {state: {params}}} = this.props;
return <SomeComponent {...params} {...this.props} />;
}
}
},
setContainer: (container) => {
_container = container;
},
reset: (routeName, params) => {
_container.dispatch(
NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({
type: "Navigation/NAVIGATE",
routeName,
params
})
]
})
);
},
goBack: () => {
_container.dispatch(NavigationActions.back());
},
navigate: (routeName, params) => {
_container.dispatch(
NavigationActions.navigate({
type: "Navigation/NAVIGATE",
routeName,
params
})
);
},
navigateDeep: (actions) => {
_container.dispatch(
actions.reduceRight(
(prevAction, action) =>
NavigationActions.navigate({
type: "Navigation/NAVIGATE",
routeName: action.routeName,
params: action.params,
action: prevAction
}),
undefined
)
);
},
getCurrentRoute: () => {
if (!_container || !_container.state.nav) {
return null;
}
return _container.state.nav.routes[_container.state.nav.index] || null;
}
};
In your parent component when you mount the navigation call following:-
"use strict";
import React from "react";
import App from "./routes";
import {navigation} from "utils";
class Setup extends React.Component {
render () {
return (
<App
ref={navigatorRef => {
navigation.setContainer(navigatorRef);
}}
/>
);
}
}
export default App;
Now, in your components you can directly use helpers from this script itself and navigation would be accessibly globally now.
import {navigate} from "utils/navigation";
For more details you can this thread
Your logout function is declared outside of the Navigator. This means you don't have access to the navigation prop there. However, your customDrawerComponent is a screen of your Navigator and it should have access to it.
So you can try something like this (props here are the props passed to the customDrawerComponent):
onPress={()=> {props.navigation.navigate("Login")}}
Plus your App.js seems kind of strange since you're not exporting any component. Have you pasted the whole code of App.js or just parts of it?
I have a <TextElement> component that displays different static text based on the language that is set. The multi language text JSON and current language is set in the Redux store.
I would like this <TextElement> component to work in the header for page title, ie in navigationOptions. However this.props.texts or this.props.language are undefined which is what would normally be used in the component. I tried the solutions on here to no avail.
class PreviousBookingsList extends Component {
static navigationOptions = function (props) {
return {
title: <TextElement textId={2} texts={this.props.texts} language={this.props.language} />,
headerRight: <Icon name="menu" color='#fff' iconStyle={styles.menuIcon} underlayColor='transparent'
size={30} onPress={() => props.navigation.openDrawer()}/>
}
};
render() {
const data = this.props.data;
const villaList = data.PreviousBookings.map(function(villa) {
return (
<Villa key={villa.VillaName} {...villa} />
);
});
return (
<View style={styles.mainBg}>
<ScrollView>
{villaList}
</ScrollView>
</View>
);
}
}
function mapStateToProps(state) {
return {
texts: state.textsReducer.texts,
data: state.dataReducer.data,
language: state.languageReducer.language
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(Actions, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(PreviousBookingsList);
Any help appreciated.
Using react-navigation, in order to achieve this:
I am nesting TabNavigator inside a StackNavigator. Code as follow:
const HomeTabs = TabNavigator(
{
Portfolio: { screen: PortfolioScreen },
Holding: { screen: HoldingScreen }
},
{
//other configs
}
)
const RootNavigator = StackNavigator(
{
Home: { screen: HomeScreen },
},
{
// other configs
}
)
//in App.js render()
return (
<Provider store={Store}>
<View style={{flex: 1}}>
<RootNavigator />
</View>
</Provider>
)
Now, I need a Floating Action Button on both Portfolio and Holding tabs. I do not want to add it twice in both PortfolioScreen and HoldingScreen components.
Is there a way where I can customize the HomeTabs component produced by TabNavigator? Like giving it extra stuffs to render? Is there a HOC API that I am missing? Something like:
class CustomizedHomeTabs extends React.Component {
onFabPress = () => { // do stuffs }
render() {
return (
<FAB onPress={this.onFabPress}></FAB>
)
}
}
export default withTabNavigator(routes, config)(CustomizedHomeTabs) //something like this would be cool!
I'm very new to learning react and was simply following this example:
https://facebook.github.io/react-native/docs/navigation.html
import { StackNavigator, } from 'react-navigation';
const App = StackNavigator(
{ Home: { screen: HomeScreen }, Profile: { screen: ProfileScreen }, });
class HomeScreen extends React.Component {
static navigationOptions = { title: 'Welcome', };
render() {
const { navigate } = this.props.navigation;
return ( <Button title="Go to Jane's profile" onPress={() => navigate('Profile', { name: 'Jane' }) } /> ); }
}
But when I run this I get an error that says
"ProfileScreen is not defined"
I can't see what to do here since this wasn't on the documents page I linked to.
You are simply missing a React component called ProfileScreen. You have a HomeScreen:
class HomeScreen extends React.Component {
static navigationOptions = { title: 'Welcome', };
render() {
const { navigate } = this.props.navigation;
return (
<Button
title="Go to Jane's profile"
onPress={() => navigate('Profile', { name: 'Jane' }) }
/>
);
}
}
Now just define some kind of ProfileScreen:
const ProfileScreen = () => (
<View>
<Text>ProfileScreen</Text>
</View>
);