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>
);
}
Related
Hello I have a problem with re rendering the component below you can see my code for the first screen within that I have a custom component:
class Ahelle extends React.Component{
constructor(props){
super(props)
this.state={
mamad:10
}
}
render(){
return (
<View style={{backgroundColor:"white"}}>
<ScrollView>
<CustomSlider defaultValue={0} />
<CustomSlider defaultValue={this.state.mamad} disabled={true}/>
<TouchableOpacity style={{width:100,height:100,alignSelf:"center"}} onPress={()=>{this.setState({mamad:20})}}><Text>dddd</Text></TouchableOpacity>
</ScrollView>
</View>
);
}
}
Here I have a custom component and I pass a default value for showing but when I change the state , it is not changing the value I passed as props.
here is my custom slider component and its state, props and any other details.
class Test extends React.Component{
constructor(props){
console.log(props)
super(props)
this.state = {
value: props.defaultValue
};
}
render(){
return(
<Slider
style={{width: wp("70%")}}
value={this.state.value}
/>
)
}
}
export default Test;
SEE THE PROBLEM IN ACTION
Thank you for your time
Your slider component never does anything with updated prop values that are passed. Coincidentally, it's also a react anti-pattern to store passed props in local component state. You can, and should, consume them directly. Just pass this.state.mamad to the value prop and consume. You can also pass along any additional props by spreading them in to the slider component.
class Test extends React.Component {
render() {
return (
<Slider
style={{ width: wp("70%") }}
value={this.props.value}
{...this.props}
/>
);
}
}
export default Test;
Usage
<CustomSlider value={this.state.mamad} disabled={true} />
If you really wanted to store the passed defaultValue prop and keep it updated, then implement the componentDidUpdate lifecycle function. Note, this is not the recommended solution.
class Test extends React.Component {
constructor(props) {
console.log(props);
super(props);
this.state = {
value: props.defaultValue
};
}
componentDidUpdate(prevProps) {
const { defaultValue } = this.props;
if (prevProps.defaultValue !== defaultValue) {
this.setState({ value: defaultValue});
}
}
render() {
return <Slider style={{ width: wp("70%") }} value={this.state.value} />;
}
}
export default Test;
Your code is correct. I tested it.
App.js
import React from "react";
import { Text, View, ScrollView, TouchableOpacity } from "react-native";
import CustomSlider from "./CustomSlider";
export default class Ahelle extends React.Component {
constructor(props) {
super(props);
this.state = {
mamad: 10,
};
}
render() {
return (
<View style={{ backgroundColor: "white" }}>
<ScrollView>
<CustomSlider defaultValue={0} />
<CustomSlider defaultValue={this.state.mamad} disabled={true} />
<TouchableOpacity
style={{ width: 100, height: 100, alignSelf: "center" }}
onPress={() => {
this.setState({ mamad: 20 });
}}
>
<Text>dddd</Text>
</TouchableOpacity>
</ScrollView>
</View>
);
}
}
CustomSlider.js
import React from "react";
import { Text } from "react-native";
export default class CustomSlider extends React.Component {
render() {
return <Text>defaultValue: {this.props.defaultValue}</Text>;
}
}
Result:
View Result
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')
I have the following setup:
import {getNewImage} from '...'
export default class FirstClass extends Component {
constructor() {
super();
this.state = {
imageURL: 'www.test.com/new.jpg',
}
}
update = () => {
this.setState({
imageURL: 'www.test.com/updated.jpg',
})
}
render() {
return (
<View>
<Image
source={{ uri: this.state.imageURL }}
/>
</View>
);
}
}
import Class1 from '...'
export default class SecondClass extends Component {
render() {
return (
<TouchableOpacity onPress={() => new FirstClass().update()}>
<Class1></Class1>
</TouchableOpacity>
);
}
}
The problem is: it doesn't update the imageURL. I tried multiple things. Logging this inside of update gave back the right object. But trying to log the this.setState() gives an undefinded back.
I suppose by Class1 you mean FirstClass.
you should use the reference of the component using ref, not creating new instance of FirstClass class
checkout this code
export default class SecondClass extends Component {
private firstClass = null;
render() {
return (
<TouchableOpacity onPress={() => this.firstClass.update()}>
<Class1 ref={ref => this.firstClass = ref} />
</TouchableOpacity>
);
}
}
You can try to update state in Class1 similar to what do you want by the react reference.
But on my opinion this is non a good case and predictable behavior to change child component state from parent.
As another options you can add additional state to the SecondClass and pass it via props to child component. And inside Class1 in getDerivedStateFromProps based on that prop change state.
export default class FirstClass extends Component {
constructor() {
super();
this.state = {
isNeedToUdpate: false,
imageURL: "www.test.com/new.jpg"
};
}
static getDerivedStateFromProps(props, state) {
if (props.isNeedToUdpate !== state.isNeedToUdpate) {
return {
isNeedToUdpate: props.isNeedToUdpate,
imageURL: "www.test.com/updated.jpg"
};
}
return null;
}
render() {
return (
<View>
<Image source={{ uri: this.state.imageURL }} />
</View>
);
}
}
export default class SecondClass extends Component {
constructor() {
super();
this.state = {
isNeedToUpdateClass1: false
};
}
render() {
return (
<TouchableOpacity
onPress={() => {
this.setState({ isNeedToUpdateClass1: true });
}}
>
<Class1 isNeedToUpdate={this.state.isNeedToUpdateClass1}></Class1>
</TouchableOpacity>
);
}
}
I have 2 screens, my Home Screen
class Home extends Component {
constructor(props) {
super(props)
this.state = {
myDebts: 745.8455656,
debts: 1745.54555
}
}
addFriendsHandler = () => {
Alert.alert('You tapped the button!')
}
render () {
return (
<View style={{flex: 1}}>
<Header
text={"Splitwise"} />
<Debts
myDebts={this.state.myDebts}
debts={this.state.debts}/>
<Buttons text={"+ ADD FRIENDS ON SPLITWISE"}
clicked={() => this.props.navigation.navigate("AddFriend")}/>
</View>
)
}
}
export default Home
and my second Screen
class AddFriendPage extends Component{
state = {
name: ''
}
addFriendHandler = () => {
this.props.navigation.navigate("MainPage")
}
render() {
return (
<View>
<Header text={"Add a friend"}/>
<Sae
label={'Your friends name'}
labelStyle={{ color: '#47AE4f' }}
iconClass={FontAwesomeIcon}
iconName={'pencil'}
iconColor={"#47AE4f"}
inputStyle={{ color: '#000' }}
onBlur={(e) => this.setState({name: e.nativeEvent.text})}
/>
<Buttons text={"+ ADD FRIEND"}
disable={this.state.name === ''}
clicked={this.addFriendHandler}/>
</View>
)
}
}
and my Navigator
export default class App extends React.Component {
render() {
return (
<AppStackNavigator />
);
}
}
const AppStackNavigator = createStackNavigator({
MainPage: Home,
AddFriend: AddFriendScreen
})
I want to send a function to the AddFriendPage screen from Home screen, and inside that function i want to get value from input and return the name back into Home screen, but unfortunately i have no idea how to share data between 2 screens
https://reactnavigation.org/docs/en/params.html#docsNav
You want to pass params during navigation:
() => this.props.navigation.navigate("AddFriend", {name: "Alan"})
Then in the parent method (if you want to display it, you could just put it in render):
const name = this.props.navigation.getParam(name, null)
If null, you know that the screen was reached from a different screen, and can handle that case normally. You can add whatever params you want.
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>
);
}