I have this SMN() function and I've created inside it Site function as Const. So I need to call Site function in Render() function. This is main function code:
SMN() {
const Site = () => {
return (
<View style={{ height: 400 }}>
<WebView source={{ uri: 'https://www.google.com' }} style={{ marginTop: 20 }} />
</View>
);
}
});
This is Render() function where I want to call Site function from it, I've used:
this.SMN().Site , this does not throw errors but does not display any.
render() {
return (
</View>
<View>{this.SMN().Site}</View>
</View>
)
}
Make your Site as a component just like this:
const Site = () => {
return (
<View style={{ height: 400 }}>
<WebView
source={{ uri: 'https://www.google.com' }}
style={{ marginTop: 20 }} />
</View>
);
}
And in your render function use it like this:
render() {
return (
</View>
<View><Site /></View>
</View>
)
}
I think you want to get the return you want from SMN(). So this is what I thought your intended solution was.
SMN() {
return (
{
Site : () => (
<View style={{ height: 400 }}>
<WebView source={{ uri: 'https://www.google.com' }}
style={{marginTop:20 }} />
</View>
)
}
);
});
render() {
return (
</View>
<View>{this.SMN().Site}</View>
</View>
)
}
Related
Currently, I am using this logic to render data on the basis of results from a grapqhl query. This works fine:
const contacts = () => {
const { loading, error, data } = useUsersQuery({
variables: {
where: { id: 1 },
},
});
if (data) {
console.log('DATA COMING', data);
const contactName = data.users.nodes[0].userRelations[0].relatedUser.firstName
.concat(' ')
.concat(data.users.nodes[0].userRelations[0].relatedUser.lastName);
return (
<View style={styles.users}>
<View style={styles.item} key={data.users.nodes[0].id}>
<Thumbnail
style={styles.thumbnail}
source={{
uri:
'https://cdn4.iconfinder.com/data/icons/avatars-xmas-giveaway/128/girl_avatar_child_kid-512.png',
}}></Thumbnail>
<Text style={styles.userName}>{contactName}</Text>
</View>
</View>
);
}
};
return (
<SafeAreaView style={{ flex: 1 }}>
<Container style={{ flex: 1, alignItems: 'center' }}>
<Item style={styles.addToWhitelist}>
<Icon name="add" onPress={() => navigation.navigate('AddContact')} />
<Text style={styles.addToContactTitle}>Add contact</Text>
</Item>
<Text onPress={() => navigation.navigate('Home')}>Zurück</Text>
<View style={{ width: moderateScale(350) }}>
<Text>Keine Kontacte</Text>
</View>
{contacts()}
{/* <ContactList data={userData}></ContactList> */}
</Container>
</SafeAreaView>
);
};
However, when I make a separate component :
export const ContactList: React.FunctionComponent<UserProps> = ({
data,
}) => {
console.log('user called');
if (!data) return null;
console.log('DATA COMING', data);
const contactName = data.users.nodes[0].userRelations[0].relatedUser.firstName
.concat(' ')
.concat(data.users.nodes[0].userRelations[0].relatedUser.lastName);
return (
<View style={styles.users}>
<View style={styles.item} key={data.users.nodes[0].id}>
<Thumbnail
style={styles.thumbnail}
source={{
uri:
'https://cdn4.iconfinder.com/data/icons/avatars-xmas-giveaway/128/girl_avatar_child_kid-512.png',
}}></Thumbnail>
<Text style={styles.userName}>{contactName}</Text>
</View>
</View>
);
};
and call it like this:
const [userData, setUserData] = useState<UsersQueryHookResult>('');
const contacts = () => {
console.log('running');
const { loading, error, data } = useUsersQuery({
variables: {
where: { id: 1 },
},
});
if (data) {
setUserData(data);
}
};
return (
<SafeAreaView style={{ flex: 1 }}>
<Container style={{ flex: 1, alignItems: 'center' }}>
<Item style={styles.addToWhitelist}>
<Icon name="add" onPress={() => navigation.navigate('AddContact')} />
<Text style={styles.addToContactTitle}>Add contact</Text>
</Item>
<Text onPress={() => navigation.navigate('Home')}>Zurück</Text>
<View style={{ width: moderateScale(350) }}>
<Text>Keine Kontacte</Text>
</View>
{/* {contacts()} */}
<ContactList data={userData}></ContactList>
</Container>
</SafeAreaView>
);
};
However, this gives me a too many re-renders issue. What am I missing? Probably something basic. I also tried using useEffects but I can't run a graphql query hook inside it. That gives me an invalid hook call error.
It seems your running in an endless recursion.
If you call contacts in you render block it causes a setState (through setUserData) which renders, so contacts is called once again and so on till infinite (or till the error).
I created a GoToButton as advised by React Navigation v5 to move from one child screen to another
function GoToButton({ screenName }) {
const navigation = useNavigation();
return (
<TouchableOpacity
title={`${screenName}`}
onPress={() => navigation.navigate(screenName)} style={styles.buttonLogin}>
<Text style={{color: '#ffcc00', fontWeight: 'bold'}}>Start!</Text>
</TouchableOpacity>
);
}
I wanted to move from the login screen which was imported inside of the function:
function LoginScreen({navigation}) {
return (
<View>
<Login />
<View style={{alignContent:'center' , alignItems:'center'}}>
<GoToButton screenName="TabNavigator" />
</View>
</View>
);
}
To the TabNavigatorScreen:
function TabNavigatorScreen({ navigation }) {
return (
<TabNavigator/>
);
}
When I place the reference to the GoToButton like this, the reference works:
function LoginScreen({navigation}) {
return (
<View>
<Login /> //imported earlier from the file Login.js
<View style={{alignContent:'center' , alignItems:'center'}}>
<GoToButton screenName="TabNavigator" /> //next to the imported Login
</View>
</View>
);
}
But my goal is to place the GoToButton inside of the Login.js as shown:
import GoToButton from '../navigation/SwitchNavigator' class Login extends React.Component {
login = () => {
this.props.login(this.props.email)
}
render() {
return (
<View style={{ position: 'absolute', justifyContent: 'center', alignItems: 'center', flex: 1, justifyContents: "flex-end", width: screenWidth, height: screenHeight, backgroundColor: 'white', }}>
<View style={styles.box}>
<TextInput value={this.props.user} style={styles.textarea} onChangeText={input => this.props.updateEmail(input)}
placeholder='Email'/>
<TextInput value={this.props.user} style={styles.textarea} onChangeText={input => this.props.updatePassword(input)}
placeholder='Password' />
<GoToButton screenName="TabNavigator" onPress={() => this.login()}/>
</View>
</View>
);
}
}
Unfortunately, this results in the error: ooks like you nested a 'Navigation Container' inside another. How do I solve this problem?
I have multiple functions that looks almost identical. How can I refactor my function so that I don't have write multiple functions.
This is my code:
renderImage = () => {
var imgSource = this.state.image? imageOne : imageTwo;
return (
<View style={{marginLeft:20, marginTop:20,width:50, height:67, backgroundColor:'transparent', alignItems:'center'}}>
<Image
style={{width:46, height:46}}
source={ imgSource }
/>
<Text style={{paddingTop:4, fontSize:11, color:'#4a4a4a'}}>some text</Text>
</View>
);
}
I have another function that looks very similar:
renderImage2 = () => {
var imgSource = this.state.image2? imageThree : imageFour;
return (
<View style={{marginLeft:20, marginTop:20,width:50, height:67, backgroundColor:'transparent', alignItems:'center'}}>
<Image
style={{width:46, height:46}}
//I want to change source
source={ imgSource }
/>
//Also I want to change text
<Text style={{paddingTop:4, fontSize:11, color:'#4a4a4a'}}>some other text</Text>
</View>
);
}
I just want to change the Image source and the text. Can I do this?
Create another component that returns the render but takes 2 props you pass in (source, text)
import React from 'react';
import { Image, Text, View } from 'react-native';
class ImageWithText extends React.PureComponent {
render() {
const { source, text } = this.props;
return (
<View style={{ marginLeft: 20, marginTop: 20, width: 50, height: 67, backgroundColor: 'transparent', alignItems: 'center' }}>
<Image style={{ width: 46, height: 46 }} source={source} />
<Text style={{ paddingTop: 4, fontSize: 11, color: '#4a4a4a' }}>{text}</Text>
</View>
);
}
}
export default ImageWithText;
and when you want to use the new component
renderImage = () => {
var imgSource = this.state.image? imageOne : imageTwo;
return (
<ImageWithText source={imgSource} text="some text">
);
}
You can first define a renderImage function that takes in a parameter to do decision making. Within this renderImage function, define all the possible images to load within a lookup object, such as below
renderImage = (renderImage) => {
const lookup = {
image_1: { src: imageOne, text: 'text_for_image_one' },
image_2: { src: imageTwo, text: 'text_for_image_two' }
}
const selectedImage = lookup[renderImage] || undefined;
if(!selectedImage) return;
return (
<View style={{marginLeft:20, marginTop:20,width:50, height:67, backgroundColor:'transparent', alignItems:'center'}}>
<Image
style={{width:46, height:46}}
source={selectedImage.src}
/>
<Text style={{paddingTop:4, fontSize:11, color:'#4a4a4a'}}>{selectedImage.text}</Text>
</View>
);
}
Then within your render method do below
render() {
...
{this.renderImage(image_1)}
{this.renderImage(image_2)}
...
}
You can define simple function render like
renderImage = (imageSrc, text) => (
<View style={{marginLeft:20, marginTop:20,width:50, height:67, backgroundColor:'transparent', alignItems:'center'}}>
<Image
style={{width:46, height:46}}
//I want to change source
source={ imageSrc }
/>
//Also I want to change text
<Text style={{paddingTop:4, fontSize:11, color:'#4a4a4a'}}>{text}</Text>
</View>
)
end use in your render like:
{this.renderImage(this.state.image? imageOne : imageTwo, 'some text')}
Whenever I tried to build UI from scratch I'm getting this error adjacent jsx element must be wrapped in an enclosing tag. I don't know how to solve this. Because I tried different methods, I've tried to put the blocks within View component withflex:1 but non-use. Is there any proper solution for this. This is becoming a great challenge for me because I can't design any components of my own. What to do please help me. Following is my code.
screen.js
export default class FirstScreen extends Component {
constructor(props){
super(props);
this.state = {
showPopupDialog: false,
workType: "",
workers: []
}
}
componentWillMount(){
fetch('http://192.168.1.6:3000/api/worker', {
method:'GET',
headers:{
Accept: 'application/json'
}
})
.then(response => response.json())
.then(responseData =>
this.setState({
workers:responseData
})
)
}
onPressYes = (workType) => {
console.log(workType);
}
popupDialog = (id, workType) => {
this.setState ({
showPopupDialog: true,
workType: workType
});
//make sure you set showPopupDialog to false and workType to "" when you click yes or no button in PopupDialog component so that it will work the next time you click on card
}
render() {
const { workers, workType, showPopupDialog} = this.state;
return (
<View style={{flex:1}}>
<Header />
<ScrollView>
{workers.map((a, index)=> (
<View style={{flex:1}}>
<CardSection>
<TouchableOpacity onPress={() => this.popupDialog(a.id, a.work_type)}>
<View style={{ maringTop: 10, marginLeft:120}}>
<Image style={{ height: 100, width: 100 }} source={{ uri: a.work_type == 'Carpenter' ? images[0].image : images[1].image}}/>
<Text style={{marginLeft:20, fontSize:20}}>{a.work_type}</Text>
</View>
</TouchableOpacity>
</CardSection>
</View>
))}
{showPopupDialog && <PopupDialog
dialogStyle={{ backgroundColor: "#FFFFFF", height: 180, width:300, borderWidth:1,padding:10}}
overlayBackgroundColor="#fff" dismissOnTouchOutside={true}>
<View style={styles.dialogContentView}>
<Text style={{fontSize:18, margingTop:10,color:"#000000"}}>Are you sure you want to submit?</Text>
<View style={{flexDirection:'row'}}>
<View style={styles.button_1}>
<Button title="Yes" color="#FF6633" onPress={() => this.onPressYes(workType)}/>
</View>
<View style={styles.button_1}>
<Button title="No" color="#FF6633" onPress={() =>this._onPressNo() }/>
</View>
</View>
</View>
</PopupDialog>}
</ScrollView>
</View>
);
}
}
The issue I'm facing is I can't place the <PopupDialog> component adjacent to <CardSection> , in order to that I put the <PopupDialog> within <View> ,even though it doesn't solve my issue.Please help..Please
Give a try with below corrected code.
There are two things that needs be corrected
You are doing .map but you are not returning anything which I have
corrected in the code below
export default class FirstScreen extends Component {
constructor(props){
super(props);
this.state = {
workType: "",
workers: []
}
}
componentWillMount(){
fetch('http://192.168.1.6:3000/api/worker', {
method:'GET',
headers:{
Accept: 'application/json'
}
})
.then(response => response.json())
.then(responseData =>
this.setState({
workers:responseData
})
)
}
onPressYes = (workType) => {
console.log(workType);
}
popUpDialog = (id, workType) => {
this.setState ({
workType: workType
});
this.popupDialog.show();
//make sure you set workType to "" when you click yes or no button in PopupDialog component so that it will work the next time you click on card
}
render() {
const { workers, workType} = this.state;
return (
<View style={{flex:1}}>
<Header />
<ScrollView>
{workers.map((a, index)=> (
<View style={{flex:1}}>
<CardSection>
<TouchableOpacity onPress={() => this.popUpDialog(a.id, a.work_type)}>
<View style={{ maringTop: 10, marginLeft:120}}>
<Image style={{ height: 100, width: 100 }} source={{ uri: a.work_type == 'Carpenter' ? images[0].image : images[1].image}}/>
<Text style={{marginLeft:20, fontSize:20}}>{a.work_type}</Text>
</View>
</TouchableOpacity>
</CardSection>
</View>
))}
<PopupDialog ref={popupDialog => {
this.popupDialog = popupDialog;
}}
dialogStyle={{ backgroundColor: "#FFFFFF", height: 180, width:300, borderWidth:1,padding:10}}
overlayBackgroundColor="#fff" dismissOnTouchOutside={true}>
<View style={styles.dialogContentView}>
<Text style={{fontSize:18, margingTop:10,color:"#000000"}}>Are you sure you want to submit?</Text>
<View style={{flexDirection:'row'}}>
<View style={styles.button_1}>
<Button title="Yes" color="#FF6633" onPress={() => this.onPressYes(workType)}/>
</View>
<View style={styles.button_1}>
<Button title="No" color="#FF6633" onPress={() =>this._onPressNo() }/>
</View>
</View>
</View>
</PopupDialog>
</ScrollView>
</View>
);
}
}
If I understand your question correctly...
You can return multiple root elements in jsx by wrapping is in a <React.Fragment> element (you can use <> and </> in v16.2 and later). Fragments are new in React v16. Prior to that, you just have to wrap them in some element (a div or span, usually).
The problem is that you have this structure:
<a>
{this.state.workers.map((a, index)=>
<b/>
<c/>
)}
</a>
Since <b/><c/> is parsed separately and there's no enclosing element, you're getting the error. But an enclosing element isn't necessary for the final structure, which does have an enclosing element. The solution is to simply return an array of JSX elements, like this:
<a>
{this.state.workers.map((a, index)=>
[<b/>,
<c/>]
)}
</a>
I am fetching data from http://retailsolution.pk/api/allhome I want to display the title of the product and then all the child products below it, I am getting this output: Here's my code:
class App extends Component {
constructor(props) {
super(props);
this.state = {
Deals: []
};
}
componentWillMount() {
axios
.get("https://retailsolution.pk/api/allhome")
.then(response => this.setState({ Deals: response.data.Deals }));
}
_renderItem(item) {
return (
<View style={{ width: 100, height: 130 }}>
<Image
style={{ width: 100, height: 100 }}
source={{ uri: item.image }}
/>
<Text numberOfLines={1} style={{ flex: 1 }}>
{" "}
{item.name}
</Text>
</View>
);
}
renderTitle() {
return this.state.Deals.map(deal => (
<Text key={deal.parent.id} style={styles.text}>
{deal.parent.name}
</Text>
));
}
renderImage() {
return this.state.Deals.map(deal => (
<FlatList
key={deal.child.product_id}
style={{ marginTop: 5 }}
horizontal
ItemSeparatorComponent={() => <View style={{ width: 5 }} />}
renderItem={({ item }) => this._renderItem(item)}
data={[deal.child]}
/>
));
}
render() {
console.log(this.state.Deals);
return (
<View style={{ flex: 1, marginLeft: 8, marginRight: 8, marginTop: 10 }}>
{this.renderTitle()}
{this.renderImage()}
</View>
);
}
}
In my case {this.renderTitle()} gets execute first and maps every value from the api to the app and then {this.renderImage()} maps all flatlists to the app.
Is there any way I can run this.renderImage() after every iteration of rhis.renderTitle()?
You will have to do it using nested loop.
Try something like this -
{this.state.Deals.map(deal => {
return (
<div>
<Text key={deal.parent.id} style={styles.text}>
{deal.parent.name}
</Text>
{deal.child.map(item => {
return (
<FlatList
key={item.product_id}
style={{ marginTop: 5 }}
horizontal
ItemSeparatorComponent={() => <View style={{ width: 5 }} />}
renderItem={({ item }) => this._renderItem(item)}
data={[item]}
/>
);
})}}
</div>
);
})}
A way to do it is to call a function after the fetch that will create the section data for the Flatlist with the correct format:
sections = [{title: 'Latest', data:["The products data array"]}, {title: 'second section', data : ["Other products"]}, and so on...]`