I made 2 screens 1st home screen and 2nd for edit screen. I want to update the values from edit screen but when I click save button it shows an error setState(...): takes an object of state variables to update or a function which returns an object of state variables and display a blank home screen. Can someone please tell me how to update value from the child class? Below is my code, please help
home.js
class Home extends Component {
state = {
modal: false,
editMode: false.
post: [
{
key: "1",
title: "A Good Boi",
des: "He's a good boi and every one know it.",
image: require("../assets/dog.jpg"),
},
{
key: "2",
title: "John Cena",
des: "As you can see, You can't see me!",
image: require("../assets/cena.jpg"),
},
],
};
addPost = (posts) => {
posts.key = Math.random().toString();
this.setState((prevState) => {
return {
post: [...prevState.post, posts],
modal: false,
};
});
};
onEdit = (data) => {
this.setState({ post: { title: data }, editMode: false });
};
render() {
if (this.state.editMode)
return <EditScreen item={item} onEdit={this.onEdit} />;
return (
<Screen style={styles.screen}>
<Modal visible={this.state.modal} animationType="slide">
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.modalContainer}>
<AddPost addPost={this.addPost} />
</View>
</TouchableWithoutFeedback>
</Modal>
<FlatList
data={this.state.post}
renderItem={({ item }) => (
<>
<TouchableOpacity
activeOpacity={0.7}
onPress={() => this.setState({ editMode: true })}
style={styles.Edit}
>
<MaterialCommunityIcons
name="playlist-edit"
color="green"
size={35}
/>
</TouchableOpacity>
<Card>
<Image style={styles.image} source={item.image} />
<View style={styles.detailContainer}>
<Text style={styles.title} numberOfLines={1}>
{item.title}
</Text>
<Text style={styles.subTitle} numberOfLines={2}>
{item.des}
</Text>
</View>
</Card>
</>
)}
/>
</Screen>
Edit.js
<KeyboardAvoidingView
behavior="position"
keyboardVerticalOffset={Platform.OS === "ios" ? 0 : 100}
>
<Image style={styles.image} source={item.item} />
<View style={styles.detailContainer}>
<AppTextInput value={item.title} />
<AppTextInput value={item.des} />
</View>
<AppButton
text="Save"
onPress={() => {
onEdit(this.state);
this.props.navigation.goBack("Home");
}}
/>
</KeyboardAvoidingView>
I'm also getting a warning
This can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use components with callbacks in your options, you can use 'navigation.setOptions' instead. See https://reactnavigation.org/docs/troubleshooting#i-get-the-warning-non-serializable-values-were-found-in-the-navigation-state for more details.
It looks as though ListDetails is not actually a child of Home. If it were you could pass the onEdit function down as props.
You should not pass it as navigation params because when you leave the Home page it will be unmounted and you won't be able to update the state.
One way to achieve what you want is to use the Context api to setup a store for your application state.
Check this out: https://reactjs.org/docs/context.html
Edit, without context:
You will need to move the ListDetails component inside the Home component as a child. You can keep a value in state to check if you are in edit mode. Something like this maybe:
class Home extends Component {
state = {
selectedItem: undefined,
modal: false,
post: [
{
key: "1",
title: "A Good Boi",
des: "He's a good boi and every one know it.",
image: require("../assets/dog.jpg"),
},
{
key: "2",
title: "John Cena",
des: "As you can see, You can't see me!",
image: require("../assets/cena.jpg"),
},
],
};
addPost = (posts) => {
posts.key = Math.random().toString();
this.setState((prevState) => {
return {
post: [...prevState.post, posts],
modal: false,
};
});
};
onEdit = (data) => {
this.setState({ post: { title: data }, editMode: false, selectedItem: undefined });
};
render() {
const { editMode, selectedItem } = this.state;
if (editMode && selectedItem) return <ListDetails item={selectedItem} onEdit={onEdit} />
return (
<Screen style={styles.screen}>
<Modal visible={this.state.modal} animationType="slide">
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.modalContainer}>
<AddPost addPost={this.addPost} />
</View>
</TouchableWithoutFeedback>
</Modal>
<FlatList
data={this.state.post}
renderItem={({ item }) => (
<>
<TouchableOpacity
activeOpacity={0.7}
onPress={() => this.setState({ editMode: true, selectedItem: item })}
style={styles.Edit}
>
<MaterialCommunityIcons
name="playlist-edit"
color="green"
size={35}
/>
</TouchableOpacity>
<Card>
<Image style={styles.image} source={item.image} />
<View style={styles.detailContainer}>
<Text style={styles.title} numberOfLines={1}>
{item.title}
</Text>
<Text style={styles.subTitle} numberOfLines={2}>
{item.des}
</Text>
</View>
</Card>
</>
Related
I made 2 screens home and editing screen. I want to change values from edit screen without redux and context but I don't know how? and also when I click save in editscreen it's throwing error that undefined is not an object (evaluating '_this.props.navigation.goBack') and displaing blank home screencwhy that's happening. Can some one help me please, below is my code
home.js
class Home extends Component {
state = {
modal: false,
editMode: false.
post: [
{
key: "1",
title: "A Good Boi",
des: "He's a good boi and every one know it.",
image: require("../assets/dog.jpg"),
},
{
key: "2",
title: "John Cena",
des: "As you can see, You can't see me!",
image: require("../assets/cena.jpg"),
},
],
};
addPost = (posts) => {
posts.key = Math.random().toString();
this.setState((prevState) => {
return {
post: [...prevState.post, posts],
modal: false,
};
});
};
onEdit = (data) => {
this.setState({ post: { title: data }, editMode: false });
};
render() {
if (this.state.editMode)
return <EditScreen item={item} onEdit={this.onEdit} />;
return (
<Screen style={styles.screen}>
<Modal visible={this.state.modal} animationType="slide">
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.modalContainer}>
<AddPost addPost={this.addPost} />
</View>
</TouchableWithoutFeedback>
</Modal>
<FlatList
data={this.state.post}
renderItem={({ item }) => (
<>
<TouchableOpacity
activeOpacity={0.7}
onPress={() => this.setState({ editMode: true })}
style={styles.Edit}
>
<MaterialCommunityIcons
name="playlist-edit"
color="green"
size={35}
/>
</TouchableOpacity>
<Card>
<Image style={styles.image} source={item.image} />
<View style={styles.detailContainer}>
<Text style={styles.title} numberOfLines={1}>
{item.title}
</Text>
<Text style={styles.subTitle} numberOfLines={2}>
{item.des}
</Text>
</View>
</Card>
</>
)}
/>
</Screen>
Edit.js
import React, { Component } from "react";
import { View, StyleSheet, Image, KeyboardAvoidingView } from "react-native";
import colors from "../config/colors";
import AppButton from "../components/AppButton";
import AppTextInput from "../components/AppTextInput";
class EditScreen extends Component {
render() {
const { item, onEdit, onClose } = this.props;
return (
<KeyboardAvoidingView
behavior="position"
keyboardVerticalOffset={Platform.OS === "ios" ? 0 : 100}
>
<Image style={styles.image} source={item.image} />
<View style={styles.detailContainer}>
<AppTextInput value={item.title} />
<AppTextInput value={item.des} />
</View>
<AppButton
text="Save"
onPress={() => {
onEdit(this.state);
}}
/>
</KeyboardAvoidingView>
);
}
}
export default EditScreen;
AppTextInput.js
function AppTextInput({ icon, width = "100%", ...otherProps }) {
return (
<View style={[styles.container, { width }]}>
<TextInput
placeholderTextColor={defaultStyles.colors.medium}
style={defaultStyles.text}
{...otherProps}
/>
</View>
);
}
Try this:
Edit.js
import React, { Component } from 'react';
import { View, StyleSheet, Image, KeyboardAvoidingView } from 'react-native';
import colors from '../config/colors';
import AppButton from '../components/AppButton';
import AppTextInput from '../components/AppTextInput';
class EditScreen extends Component {
constructor(props) {
super(props);
this.state = { ...props.item };
}
render() {
const { onEdit, onClose } = this.props;
const { title, des, image } = this.state;
return (
<KeyboardAvoidingView
behavior="position"
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 100}>
<Image style={styles.image} source={image} />
<View style={styles.detailContainer}>
<AppTextInput
value={title}
onChangeText={text => this.setState({ title: text })}
/>
<AppTextInput
value={des}
onChangeText={text => this.setState({ des: text })}
/>
</View>
<AppButton text="Save" onPress={() => onEdit(this.state)} />
</KeyboardAvoidingView>
);
}
}
export default EditScreen;
onEdit
onEdit = data => {
const newPosts = this.state.post.map(item => {
if(item.key === data.key) return data;
else return item;
})
this.setState({ post: newPosts, editMode: false });
};
Only the direct children of a navigator can access
this.props.navigation
If you want to access that inside the edit screen you can pass it from the Home screen as a prop. Like so:
return <EditScreen item={item} onEdit={this.onEdit} navigation={this.props.navigation} />;
But i don't think you need to go back because you are still on the Home page and just rendering the EditScreen within it. So just changing the state to have editMode: false should be enough
I made 2 screens one home screen and 2nd edit screen I need to edit data of home screen from edit screen and save it and that data should also update in home and detail screen. How can I do this without redux or context. Can anyone tell me.
Home.js
class Home extends Component {
state = {
post: [
{
key: "1",
title: "A Good Boi",
des: "He's a good boi and every one know it.",
image: require("../assets/dog.jpg"),
},
],
};
render() {
return (
<FlatList
data={this.state.post}
renderItem={({ item }) => (
<>
<TouchableOpacity
activeOpacity={0.7}
onPress={() => this.props.navigation.navigate("Edit", item)}
style={styles.Edit}
>
<MaterialCommunityIcons
name="playlist-edit"
color="green"
size={35}
/>
</TouchableOpacity>
<Card
title={item.title}
subTitle={item.des}
image={item.image}
onPress={() => this.props.navigation.navigate("Details", item)}
/>
</>
)}
/>
Edit.js
class ListDetails extends Component {
render() {
const listing = this.props.route.params;
return (
<View>
<Image style={styles.image} source={listing.image} />
<View style={styles.detailContainer}>
<AppTextInput value={listing.title} />
<AppTextInput value={listing.des} />
</View>
<AppButton
text="Save"
onPress={() => this.props.navigation.goBack("Home")}
/>
</View>
Details.js
const listing = this.props.route.params;
return (
<View>
<Image style={styles.image} source={listing.image} />
<View style={styles.detailContainer}>
<Text style={styles.title}>{listing.title}</Text>
<Text style={styles.des}>{listing.des}</Text>
</View>
</View>
);
You can pass a function from your home screen to setState for it in your edit screen. In case navigating to edit screen causes the home screen unmounted, you can change the navigate method to push of stack navigator (I haven't tested yet). The code now should look like:
HomeScreen.js:
onEdit=(data)=>{
setState(...);
}
...
<TouchableOpacity
activeOpacity={0.7}
onPress={() => this.props.navigation.navigate("Edit", {item, onEdit})} //use push instead if error occured
style={styles.Edit}
>
...
Edit.js
class ListDetails extends Component {
render() {
const {item:listing, onEdit} = this.props.route.params;
return (
<View>
<Image style={styles.image} source={listing.image} />
<View style={styles.detailContainer}>
<AppTextInput value={listing.title} />
<AppTextInput value={listing.des} />
</View>
<AppButton
text="Save"
onPress={() => { onEdit(...); this.props.navigation.goBack("Home");}}
/>
</View>
I have a flat list, which gets its data source as a state. Actually, this data is from firebase, and i have been using redux. So, the data is fetched in the actions, and using callback i get the data to state.
What i want to achieve is, when there is no data found from the api, An empty list message should be show in the view. Actually , i achieved this using "ListEmptyComponent". But whats happening is the screen starts with empty message, and the spinner loads below it, and then if data found the message goes away as well as spinner.
But, what i wanted is, when the view gets rendered the first thing everyone should see is the spinner, and then if data empty spinner hides then empty list message displays.
How to achieve this ?
My Action :
export const fetchOrderHistory = (phone, callback) => {
return (dispatch) => {
dispatch({ type: START_SPINNER_ACTION_FOR_ORDER_HISTORY })
firebase.database().ref('orders/'+phone)
.on('value', snapshot => {
const snapShotValue = snapshot.val();
callback(snapShotValue);
dispatch ({ type: ORDER_HISTORY_FETCHED , payload: snapshot.val()});
dispatch({ type: STOP_SPINNER_ACTION_FRO_ORDER_HISTORY })
});
};
};
My Flat List & spinner:
<FlatList
data={this.state.historyOfOrders}
keyExtractor={item => item.uid}
ListEmptyComponent={this.onListEmpty()}
renderItem={({ item }) => (
<Card
containerStyle={{ borderRadius: 5 }}
>
<View style={styles.topContainerStyle}>
<View>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('ViewOrderScreen', {itemsOfOrder: item}) }
>
<View style={styles.viewOrderContainer}>
<View style={styles.viewOrderTextContainer}>
<Text style={styles.viewOrderTextStyle}>View Order</Text>
</View>
<Icon
name='ios-arrow-forward'
type='ionicon'
color='#ff7675'
/>
</View>
</TouchableOpacity>
</View>
</View>
</View>
</Card>
)}
/>
{this.props.isSpinnerLoading &&
<View style={styles.loading}>
<ActivityIndicator size="large" color="#03A9F4"/>
</View> }
My Call back at componentWillMount which set state:
componentWillMount() {
this.props.fetchOrderHistory((this.props.phone), (snapShotValue)=> {
const userOrderHistory = _.map(snapShotValue, (val,uid) => ({uid, ...val}))
this.setState({ historyOfOrders: userOrderHistory })
});
}
My EmptyList Message:
onListEmpty = () => {
return <View style={{ alignSelf: 'center' }}>
<Text style={{ fontWeight: 'bold', fontSize: 25 }}>No Data</Text>
</View>
}
My State:
state = { historyOfOrders: "" }
I am getting the spinner values from the reducers, using mapStateToProps.
Kindly Guide me, through
you have to do two things for that.
First, show Flatlist only if the loader is stopped. Second, set default value of this.state.historyOfOrders is null and check if this.state.historyOfOrders not null then only show Flatlist.
Here is a code:
{(!this.props.isSpinnerLoading && this.state.historyOfOrders != null) ?
(
<FlatList
data={this.state.historyOfOrders}
keyExtractor={item => item.uid}
ListEmptyComponent={this.onListEmpty()}
renderItem={({ item }) => (
<Card containerStyle={{ borderRadius: 5 }}>
<View style={styles.topContainerStyle}>
<View>
<TouchableOpacity onPress={() => this.props.navigation.navigate('ViewOrderScreen', {itemsOfOrder: item}) }>
<View style={styles.viewOrderContainer}>
<View style={styles.viewOrderTextContainer}>
<Text style={styles.viewOrderTextStyle}>View Order</Text>
</View>
<Icon
name='ios-arrow-forward'
type='ionicon'
color='#ff7675'
/>
</View>
</TouchableOpacity>
</View>
</View>
</Card>
)}
/>
) : null
}
With this condition, even if you want loader above Flatlist you can do that.
The path you should take is rendering only the spinner when the loading flag is set and rendering the list when loading flag is false.
Your render method should be like below
render()
{
if(this.props.isSpinnerLoading)
{
return (<View style={styles.loading}>
<ActivityIndicator size="large" color="#03A9F4"/>
</View> );
}
return (/** Actual List code here **/);
}
So what I do now: I am using Firebase for my React Native project.
The user writes another user's email in . Then there is a check if this email exists in database. If the email exists, then it writes as an array to users=[] in state and should be rendered in FlatList.
Everything works fine except one thing: FlatList doesn't render anything though I have an array.
That's what I receive from console.log(users):
[{...}]
0:
email: "test#gmail.com"
id: "-LSVedv_anPyD3We-4_Q"
That's how my code looks like:
state = {
promptVisible: false,
loading: false,
users: []
};
findUserEmail = (email) => {
firebase.database()
.ref(`/users`)
.orderByChild("email")
.equalTo(email)
.once("value")
.then(snapshot => {
if (snapshot.val()) {
const value = snapshot.val()
this.setState({ users: Object.keys(value).map((id) => ({
id,
...value[id]
})), promptVisible: false})
} else {
Alert.alert("Email doesn't exist")
}
})
}
renderItem({item}) {
return (
<View style = {styles.contactContainer}>
<View style={styles.userRow}>
<View style={styles.userImage}>
<Avatar
width={60}
rounded
source={{
uri: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/60/Matterhorn_from_Domhütte_-_2.jpg/1200px-Matterhorn_from_Domhütte_-_2.jpg"
}}
/>
</View>
<View>
<View style={styles.emailBackground}>
<Text
style = {styles.contact} >
{item.email}
</Text>
</View>
<Text
style = {styles.message} >
Da inne lauft öpis...
</Text>
</View>
</View>
</View>
)
}
render() {
console.log(this.state.users);
if (this.state.loading) {
return (
<View style={{alignItems: 'center', justifyContent: 'center', flex: 1}}>
<ActivityIndicator size="large" color="dodgerblue" />
</View>
)
}
return (
<View style={styles.container}>
<Header
centerComponent={{ text: 'Nachrichten', style: { color: '#FF0000', fontSize: 20, fontWeight: 'bold' } }}
outerContainerStyles={{ backgroundColor: '#ffffff' }}
rightComponent={this.renderButton()}
/>
<View style = {styles.contentContainer}>
<FlatList
data={this.state.users}
renderItem={this.renderItem}
keyExtractor={item => item.email}
/>
</View>
<Prompt
title="Email eingeben"
placeholder="Email"
visible={this.state.promptVisible}
onCancel={() => this.setState({promptVisible: false})}
onSubmit={(email) => this.findUserEmail(email)} />
</View>
);
}
So the question is what do I do wrong? And how can I fix it?
So I found an error. That was too simple and dumb in the same way.
I just deleted this component in render and everything worked fine.
<View style = {styles.contentContainer}>
Try replacing this...
<FlatList
data={this.state.users}
renderItem={this.renderItem}
keyExtractor={item => item.email}
/>
With a static, object-filled array in the shape of what you expect this.state.users to look like. Here's an example...
<FlatList
data={[{id: "A", email: "testA#gmail.com"},{id: "B", email: "testB#gmail.com"}]}
renderItem={this.renderItem}
keyExtractor={item => item.email}
/>
This won't solve your problem, but it's what I was suggesting as a troubleshooting step.
I have a View that contains a button - onPress it opens a modal showing a list of contacts.
onPress of any of those contacts (pickContact function) I would like to dynamically add a new View to _renderAddFriendTile (above button).
Also ideally, the 'Add' icon next each contact name (in the modal) should update ('Remove' icon) whether or not they are present in _renderAddFriendTile View.
What would be the best way to do it?
[UPDATED code]
import React, {Component} from 'react'
import {
Text,
View,
ListView,
ScrollView,
StyleSheet,
Image,
TouchableHighlight,
TextInput,
Modal,
} from 'react-native'
const friends = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
}).cloneWithRows([
{
id: 1,
firstname: 'name01',
surname: 'surname01',
image: require('../images/friends/avatar-friend-01.png')
},
{
id: 2,
firstname: 'name02',
surname: 'surname02',
image: require('../images/friends/avatar-friend-02.png')
},
{
id: 3,
firstname: 'name03',
surname: 'surname03',
image: require('../images/friends/avatar-friend-03.png')
},
{
id: 4,
firstname: 'name04',
surname: 'surname04',
image: require('../images/friends/avatar-friend-04.png')
},
])
class AppView extends Component {
state = {
isModalVisible: false,
contactPicked: [],
isFriendAdded: false,
}
setModalVisible = visible => {
this.setState({isModalVisible: visible})
}
pickContact = (friend) => {
if(this.state.contactPicked.indexOf(friend) < 0){
this.setState({
contactPicked: [ ...this.state.contactPicked, friend ],
})
}
if(this.state.contactPicked.indexOf(friend) >= 0){
this.setState({isFriendAdded: true})
}
}
_renderAddFriendTile = () => {
return(
<View style={{flex: 1}}>
<View style={[styles.step, styles.stepAddFriend]}>
<TouchableHighlight style={styles.addFriendButtonContainer} onPress={() => {this.setModalVisible(true)}}>
<View style={styles.addFriendButton}>
<Text style={styles.addFriendButtonText}>Add a friend</Text>
</View>
</TouchableHighlight>
</View>
</View>
)
}
render(){
return (
<ScrollView style={styles.container}>
<Modal
animationType={'fade'}
transparent={true}
visible={this.state.isModalVisible}
>
<View style={styles.addFriendModalContainer}>
<View style={styles.addFriendModal}>
<TouchableHighlight onPress={() => {this.setModalVisible(false)}}>
<View>
<Text style={{textAlign:'right'}}>Close</Text>
</View>
</TouchableHighlight>
<ListView
dataSource={friends}
renderRow={(friend) => {
return (
<TouchableHighlight onPress={() => {this.pickContact()}}>
<View style={[styles.row, styles.friendRow]}>
<Image source={friend.image} style={styles.friendIcon}></Image>
<Text style={styles.name}>{friend.firstname} </Text>
<Text style={styles.name}>{friend.surname}</Text>
<View style={styles.pickContainer}>
<View style={styles.pickWrapper}>
<View style={this.state.isFriendAdded ? [styles.buttonActive,styles.buttonSmall]: [styles.buttonInactive,styles.buttonSmall]}>
<Image source={this.state.isFriendAdded ? require('../images/button-active.png'): require('../images/button-inactive.png')} style={styles.buttonIcon}></Image>
</View>
</View>
</View>
</View>
</TouchableHighlight>
)
}}
/>
</View>
</View>
</Modal>
{this._renderAddFriendTile()}
</ScrollView>
)
}
}
export default AppView
Since you need to update something dynamically, that's a clear indication you need to make use of local state for modelling that data. (Setting aside you are not using a state library management like Redux)
state = {
isModalVisible: false,
contactPicked: null,
}
Your pickContact function needs the friend data from the listView, so you need to call it with the row selected:
<TouchableHighlight onPress={() => {this.pickContact(friend)}}>
Then inside your pickContact function, update your UI with the new contactsPicked data model
pickContact = (friend) => {
this.setState({
contactPicked: friend,
});
}
That will make your component re-render and you can place some logic inside _renderAddFriendTile to render some extra UI (Views, Texts..) given the existence of value on this.state.contactPicked You could use something along these lines:
_renderAddFriendTile = () => {
return(
<View style={{flex: 1}}>
{this.state.contactPicked && (
<View>
<Text>{contactPicked.firstName}<Text>
</View>
)}
<View style={[styles.step, styles.stepAddFriend]}>
<TouchableHighlight style={styles.addFriendButtonContainer} onPress={() => {this.setModalVisible(true)}}>
<View style={styles.addFriendButton}>
<Text style={styles.addFriendButtonText}>Add a friend</Text>
</View>
</TouchableHighlight>
</View>
</View>
)
}
Notice you now hold in state the firstName of the contact picked, so point number 2 should be easy to address. Just inside renderRow of ListView, render a different Icon if friend.firstname === this.state.contactPicked.firstname
Note: Don't rely on firstname for this sort of check since you can have repeated ones and that would fail. The best solution is to provide to your list model an unique id property per contact and use that id property for checking the logic above.
Side Notes
The part {this.state.contactPicked && (<View><Text>Some text</Text></View)} is using conditional rendering. The && acts as an if so if this.state.contactPicked is truthy, it will render the view, otherwise it will render nothing (falsy and null values are interpreted by react as "nothing to render").
Of course, if you want to render more than one item dynamically, your state model should be an array instead, i.e contactsPicked, being empty initially. Every time you pick a contact you'll add a new contact object to the array. Then inside _renderAddFriendTile you can use map to dynamically render multiple components. I think you won't need a ListView, unless you wanna have a separate scrollable list.
_renderAddFriendTile = () => {
return(
<View style={{flex: 1}}>
{this.state.contactsPicked.length && (
<View>
{this.state.contactsPicked.map(contact => (
<Text>{contact.firstName}</Text>
)}
</View>
)}
<View style={[styles.step, styles.stepAddFriend]}>
<TouchableHighlight style={styles.addFriendButtonContainer} onPress={() => {this.setModalVisible(true)}}>
<View style={styles.addFriendButton}>
<Text style={styles.addFriendButtonText}>Add a friend</Text>
</View>
</TouchableHighlight>
</View>
</View>
)
}