I'm a newbie, and I created a react native app that contains a stack navigator, so I get this error when I click on a button to navigate from one page to another.
the App.js contains the app container:
export default class App extends React.Component {
render(){
return (
<AppNavigator />
);
}
}
const AppDrawerNavigator = createDrawerNavigator({
Welcome:{
screen: WelcomeScreen
},
SeConnecter: {
screen:ConnectionScreen} ,
About : {
screen: AboutScreen
},
list :{
screen: ListMed
},
});
const screens = {
Welcome:{
screen : AppDrawerNavigator
},
SeConnecter: {
screen:AppDrawerNavigator
} ,
About : {
screen: AppDrawerNavigator
},
list :{
screen: AppDrawerNavigator
},
}
const AppStackNavigator = createStackNavigator(screens,{
defaultNavigationOptions:{
title: 'MediClic',
headerTintColor :'#fff',
headerStyle :{
backgroundColor:'#3498db',
height: 100,
},
headerTitleStyle :{
justifyContent:'center',
fontSize: 30,
fontFamily: 'serif',
fontWeight:'bold'
}
}
});
const AppNavigator= createAppContainer(AppStackNavigator);
the welcome screen contains a component search that i created
class WelcomeScreen extends React.Component {
render(){
return (
<View style={styles.container}>
<Search navigation={this.props.navigation}/>
</View>
);
}
export default WelcomeScreen
and then the component search where there is a textinput + a search button customized
class Search extends React.Component{
constructor(props){
super(props)
}
render(){
return(
<KeyboardAvoidingView style ={styles.main_container} behavior='padding'>
<Text style={styles.text}>Trouvez votre Medecin!</Text>
<TextInput style={styles.text_input} placeholder='Médecin,Centre...' />
<View style={styles.btn_ctr}>
<TouchableOpacity style={styles.btn} onPress={()=>this.navigation.navigate('ListMed') }>
<Text style={styles.btn_txt}>Rechercher</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
)
}
}
Please help me i wasted a lot of times on this, i tried passing the navigation props to it didn't work
<Search navigation={this.props.navigation}/>
as you pass this.props.navigation in navigation on Search component the function call will be - this.props.navigation
<TouchableOpacity style={styles.btn} onPress={()=>this.props.navigation.navigate('ListMed') }>
not this.navigation.navigate('ListMed')
Related
i'm trying to pass an image path down to one component via react-navigation params and from that component to a third one as a prop.
This is a chat application and the structure of the components is:
ChatsMain.js --> (click on SingleChat, passing parameters when navigating) --> SingleConversation.js --> Message
I can pass 'name' as a parameter, but not the uri of an image, not even by assigning it to variables.
The name that i see on the SingleChat is passed without problems to the correspondent conversation, but when i pass the image i get the error:
'Failed prop type: Invalid prop source supplied to Image.'
I hope it's clear enough, i don't think it's the correct way to do this, but i am new to react native!
ChatsMain.js
const imageNames = {
juf: require('../assets/juf.png'),
meester: require('../assets/meester.png'),
groep: require('../assets/groep.png'),
onderwerpen: require('../assets/onderwerpen.png')
}
export default class ChatsMain extends React.Component {
render() {
return (
<SingleChat
image={imageNames.juf}
backgroundColor={yellow}
borderColor={blue}
name='Juf Elsa'
onPress={() => this.props.navigation.navigate('SingleConversation', {name: 'Juf Elsa', image: imageNames.juf})}
/>
)
SingleConversation.js
export default class SingleConversation extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('name', 'Chat'),
headerStyle: [titleBar, { backgroundColor: yellow }],
headerTitleStyle: [title, { color: blue }]
}
}
render() {
return (
<View style={chatMainContainer}>
<ScrollView style={chatsContent}>
<Message image={({navigation}) => navigation.getParam('image', 'image')} />
</ScrollView>
</View>
);
}
}
Message.js
export default class ReceivedFirst extends React.Component {
render(
){
return(
<View style={textWithPicture}>
<View style={[chatPhotoContainer, { borderColor: yellow }]}>
<Image source={this.props.image} style={{ width: 70, height: 70}} />
.....
.....
)
You can use this.props.navigation.state.params instead this.props.navigation.getParam
export default class SingleConversation extends React.Component {
constructor(props) {
super(props);
this.state = {
image: this.props.navigation.state.params.image
};
}
...
Message image={this.state.image} />
OR
You need to get a Navigation from the props.
render() {
const { navigation } = this.props
return (
<View style={chatMainContainer}>
<ScrollView style={chatsContent}>
<Message image={() => navigation.getParam('image', 'image')} />
</ScrollView>
</View>
);
}
I am following the React-Navigation tutorial, and got stuck on the section titled Header interaction with its screen component. The code in the tutorial work fine in the emulator provided at snack, but I discovered that when running locally I encountered the following error:
Warning: Failed prop type: The prop 'onPress' is marked as required in 'Button', but its value is 'undefined'.
I managed to get the code working on my local machine using expo-cli by changing the onPress event assignment in navigationOptions as follows (my snack here):
<Button
onPress={()=>{navigation.getParam('increaseCount')()}}
//onPress={navigation.getParam('increaseCount')} - as in tutorial
title="+1"
color={Platform.OS === 'ios' ? '#fff' : null}
/>
I am hoping someone might have some insight into why this is so. I checked and I am using the same version of Expo (v.32.0) locally.
App.js listing:
import React from 'react';
import { Button, Image, Platform, View, Text } from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
class LogoTitle extends React.Component {
render() {
return (
<Image
source={require('./spiro.png')}
style={{ width: 30, height: 30 }}
/>
);
}
}
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
headerTitle: <LogoTitle />,
headerRight: (
<Button
onPress={()=>{navigation.getParam('increaseCount')()}}
//onPress={navigation.getParam('increaseCount')}
title="+1"
color={Platform.OS === 'ios' ? '#fff' : null}
/>
),
};
};
componentWillMount() {
this.props.navigation.setParams({ increaseCount: this._increaseCount });
}
state = {
count: 0,
};
_increaseCount = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Text>Count: {this.state.count}</Text>
<Button
title="Go to Details"
onPress={() => {
/* 1. Navigate to the Details route with params */
this.props.navigation.navigate('Details', {
itemId: 86,
otherParam: 'First Details',
});
}}
/>
</View>
);
}
}
class DetailsScreen extends React.Component {
static navigationOptions = ({ navigation, navigationOptions }) => {
const { params } = navigation.state;
return {
title: params ? params.otherParam : 'A Nested Details Screen',
/* These values are used instead of the shared configuration! */
headerStyle: {
backgroundColor: navigationOptions.headerTintColor,
},
headerTintColor: navigationOptions.headerStyle.backgroundColor,
};
};
render() {
/* 2. Read the params from the navigation state */
const { params } = this.props.navigation.state;
const itemId = params ? params.itemId : null;
const otherParam = params ? params.otherParam : null;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Text>itemId: {JSON.stringify(itemId)}</Text>
<Text>otherParam: {JSON.stringify(otherParam)}</Text>
<Button
title="Update the title"
onPress={() =>
this.props.navigation.setParams({ otherParam: 'Updated!' })
}
/>
<Button
title="Go to Details... again"
onPress={() => this.props.navigation.navigate('Details')}
/>
<Button
title="Go back"
onPress={() => this.props.navigation.goBack()}
/>
</View>
);
}
}
const RootStack = createStackNavigator(
{
Home: {
screen: HomeScreen,
},
Details: {
screen: DetailsScreen,
},
},
{
initialRouteName: 'Home',
defaultNavigationOptions: {
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
},
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
My guess is that this is not a fatal error, just a warning.
It will happen in any case. React Navigation docs state:
React Navigation doesn't guarantee that your screen component will be mounted before the header. Because the increaseCount param is set in componentDidMount, we may not have it available to us in navigationOptions. This usually will not be a problem because onPress for Button and Touchable components will do nothing if the callback is null. If you have your own custom component here, you should make sure it behaves as expected with null for its press handler prop.
So, navigationOptions function will be called twice:
First time before componentDidMount. Here, getParam will return undefined.
Second time after componentDidMount.
What Button is complaining about, is the first time. It does not like onPress set to undefined.
You can check this with console.log from navigationOptions:
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
console.log(navigation.getParam('increaseCount'))
return {
headerTitle: <LogoTitle />,
headerRight: (
<Button
onPress={()=>{navigation.getParam('increaseCount')()}}
//onPress={navigation.getParam('increaseCount')}
title="+1"
color={Platform.OS === 'ios' ? '#fff' : null}
/>
),
};
};
In my opinion, your code is correct, while the code from the docs simply ignores this issue.
Try instead of navigation.getParam() to use navigation.navigate()
I have a component to add todos AddTodo which works fine and update the state with my added todos and I have a component TodoItems to display the todos in <FlatList/>. I'm using React Native Tab Navigator to switch between components but I'm not sure how to send the state this.state.todos from AddTodo component to TodoItems component.
I have been researching but couldn't find a solution in Tab Navigator but there are plenty of solutions for Stack Navigator.
Component AddTodo
export default class AddTodo extends Component {
constructor(props) {
super(props);
this.state = {
todoText: null,
todos: []
}
}
onAdd = () => {
if (this.state.todoText) {
this.state.todos.push({'todoItem': this.state.todoText});
this.setState({todos: this.state.todos});
}
}
render() {
return(
<View>
<TextInput onChangeText={(text) => {
this.setState({todoText: text});
}} />
<TouchableOpacity onPress={() => {
this.onAdd;
}}>
</View>
);
}
}
Component TodoItems
export default class TodoItems extends Component {
constructor(props) {
super(props);
this.state = {
todosList: []
}
}
render() {
return(
<View>
<FlatList
data={this.state.todosList}
renderItem={(item, index) => {
<Text>{item.todoItem}</Text>
}}
/>
</View>
);
}
}
Component Tabs
import {TabNavigator} from 'react-navigation';
import AddTodo from "./AddTodo";
import TodoItems from "./TodoItems";
var myTabs = TabNavigator(
{
'AddTodo':{screen: AddTodo,},
'TodoItems':{screen: TodoItems, },
},
{
tabBarPosition: 'top',
swipeEnabled: false,
tabBarOptions: {
labelStyle:{
fontSize: 13,
fontWeight: 'bold',
},
indicatorStyle: {
borderBottomColor: '#003E7D',
borderBottomWidth: 2,
},
style:{
backgroundColor: '#F30076',
elevation: 0,
},
},
});
export default myTabs;
Well I think you have two options:
You can use Redux which allows you to globalise your state objects so you can use them all over your app, but it can be rather complicated
https://redux.js.org/
Or you can render TodoItems from within AddTodo:
render() {
return(
<View>
<TextInput onChangeText={(text) => {
this.setState({todoText: text});
}} />
<TouchableOpacity onPress={() => {
this.onAdd;
}}>
</View>
<TodoItems data={this.state.todos} />
);
}
Then you can access that data from within TodoItems:
Hope this helps!
I'm trying react navigation inside my react native project. I using TabNavigator for content switching and I would like to make a fixed top bar with my logo inside, each time i swipe to change the tab content, the logo are stick on the top and not moving.
Now i just put the topcontainer inside my HomeScreen
class HomeScreen extends React.Component {
render() {
return(
<View style={styles.container}>
<View style={styles.topcontainer}>
<View style={styles.applogocontainer}>
<Image
source={require('./resources/logo.png')}
style={styles.applogo}
/>
</View>
</View>
</View>
);
}
}
class SecondScreen extends React.Component {
render() {
return(
<View style={styles.container}>
<Text style={styles.whitetext}>Second</Text>
</View>
);
}
}
class ThirdScreen extends React.Component {
render() {
return(
<View style={styles.container}>
<Text style={styles.whitetext}>Third</Text>
</View>
);
}
}
const TabNavs = TabNavigator({
Home: { screen: HomeScreen },
Second: { screen: SecondScreen },
Third: { screen: ThirdScreen },
},{
tabBarPosition:'bottom',
swipeEnabled:true,
tabBarOptions:{
tinColor: '#fff',
activeTintColor: '#eee',
inactiveTintColor: '#fff',
style: {
position: 'absolute',
backgroundColor: 'transparent',
left: 0,
right: 0,
bottom: 0,
},
indicatorStyle:{
backgroundColor:'white'
},
showIcon:true
}
}
);
Yes for topBar menu you can use navigationOptions, is best practise for it:
class MainScreen extends React.Component {
static navigationOptions = () => ({
header: (<YourComponentCustom />),
// others options see you : https://reactnavigation.org/docs/en/headers.html
});
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
// your code
);
}
}
export default MainScreen;
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
}
class SecondScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
</View>
);
}
}
const RootStack = StackNavigator(
{
Home: {
screen: HomeScreen,
},
SecondScreen: {
screen: SecondScreen,
},
},
{
initialRouteName: 'Home',
navigationOptions: {
header: (
<View style={styles.container}>
<View style={styles.topcontainer}>
<View style={styles.applogocontainer}>
<Image
source={require('./resources/logo.png')}
style={styles.applogo}
/>
</View>
</View>
</View>
)
},
}
);
You can use custom header. See detail from this
I am new to react native how can i send data from one screen to another screen using props in android not for ios my code is as below
Home.js
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
qwerty:{
data:[],
},
};
}
goPressed(navigate){
navigate("Product");
}
render() {
const { navigate } = this.props.navigation;
contents = this.state.qwerty.data.map((item) => {
return (
<View key={item.p1.id}>
<View>
<Text>{item.p1.content}</Text>
</View>
<View>
<TouchableHighlight onPress={() => this.goPressed(navigate)}>
<Text>
Go
</Text>
</TouchableHighlight>
</View>
</View>
);
});
return (
<ScrollView style={styles.container}>
{contents}
</ScrollView>
);
}
}
export default Home;
this is my home.js , I want pass data i.e {item.p1.content} to another screen i.e product.js so how can i do it what modification should i do?
Product.js
export default class Products extends Component {
static navigationOptions = {
title: "Products",
};
render() {
return (
<View style={{ flex: 1 }}>
<Text>{item.p1.content}</Text>
</View>
);
}
}
Send data to other screen
this.props.navigation.navigate('Your Screen Name' , { YourParamsName: "Foo"});
Receive data from other screen
this.props.navigation.state.params.YourParamsName
One method is to simply pass the date you are storing in 'qwerty' as a props to the next scene.
In Home.js you can modify your goPressed method to be something like...
goPressed(navigate){
navigate("Product", {passedData: this.state.qwerty.item.p1.content});
}
Then in Product.js you will need to modify the code to
render() {
return (
<View style={{ flex: 1 }}>
<Text>{this.props.passedData}</Text>
</View>
);
}