Conditional rendering in react native using map function - react-native

I am trying to build a notification page where notifications are being fetched from a remote server using the Notification function, so I initially set the notificationLoaded to false in order to use an ActivityLoader before rendering the notification to the page.
But I am confused about how I can render an ActivityLoader before the notificationLoaded state is set to true.
Thanks in advance
import React, { Component } from 'react';
import {
StyleSheet,
ScrollView,
Dimensions,
Text,
ActivityIndicator,
TouchableOpacity,
TextInput,
View,
StatusBar,
ImageBackground,
KeyboardAvoidingView,
AsyncStorage,
} from 'react-native';
import { Ionicons } from '#expo/vector-icons';
import { Font } from 'expo';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import { KeyboardAwareView } from 'react-native-keyboard-aware-view';
const { height, width } = Dimensions.get('window');
export default class Notification extends Component {
constructor(props) {
super(props);
this.state = {
notification: [],
notificationLoaded: false,
};
}
Notification = () => fetch('http://texotrack.com/api/user/notification.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'fetch',
}),
}).then(response => response.json()).then((responseJsonFromServer) => {
console.log(responseJsonFromServer);
this.setState({
notification: responseJsonFromServer,
notificationLoaded: true,
});
})
componentDidMount() {
this.Notification();
AsyncStorage.getItem('key').then((data) => {
const val = JSON.parse(data);
this.setState({
username: data.name,
photo: data.photo,
email: data.email,
userId: data.id,
address: data.address,
});
});
}
render() {
const notificationList = this.state.notification.map(data => (
<View key={data.msg_id} style={styles.notification}>
<View style={{
display: 'flex', flexDirection: 'row',
}}
>
<Text style={{ color: 'green' }}><Ionicons size={20} color="green" name="ios-notifications" /></Text>
<Text style={{
color: '#c9c9c9', fontSize: 15, fontWeight: 'bold', marginLeft: 5,
}}
>
{data.date_sent}
</Text>
</View>
<View style={styles.notificationBody}>
<Text style={{ color: '#000', fontSize: 16 }}>{data.message}</Text>
</View>
<View style={styles.lineStyle} />
</View>
));
return (
<View style={styles.container}>
<StatusBar
style={{ height: 30 }}
backgroundColor="black"
/>
<View elevation={5} style={styles.headers}>
<Text style={{
fontSize: 25, color: 'green', textTransform: 'uppercase', fontWeight: 'bold',
}}
>
Notification
</Text>
<Text style={styles.topIcon} onPress={this.GoHome}>
<Ionicons name="md-home" size={25} color="black" />
</Text>
</View>
<View style={{ flex: 1, margin: 5 }}>
<ScrollView alwaysBounceVertical contentContainerStyle={{ flexGrow: 1 }} enabled bounces>
{notificationList}
</ScrollView>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
lineStyle: {
borderWidth: 0.3,
borderColor: '#c9c9c9',
margin: 10,
},
headers: {
height: 50,
marginBottom: 10,
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
textAlignVertical: 'center',
padding: 10,
shadowColor: '#444',
shadowOffset: {
width: 0,
height: 60,
},
shadowRadius: 5,
shadowOpacity: 1.0,
backgroundColor: '#fff',
},
topIcon: {
marginTop: 3,
fontWeight: 'bold',
},
content: {
margin: 10,
flex: 1,
},
notification: {
height: 70,
padding: 10,
},
});

This is what you call conditional rendering. This can be achieved simply by using if conditions in your render function like:
render(){
// if loading true render Loader
if (this.state.notificationStateLoaded === true) {
return(
<ActivityLoader>
)
} else { // when loading false render the other component
return(
<WhateverComponentWhenDataHasArrived/>
)
}
}
React's documentation is pretty cool. Check this official link for conditional rendering
https://reactjs.org/docs/conditional-rendering.html

I dont understand what you need to do in your map function but to do a conditional rendering inside your render you can do :
<View>
{someCondition&& <Text>Hello</Text>}
</View>
else
<View>
{someCondition? <Text>Condition True</Text> : <Text>Condition false</Text>}
</View>

Related

Updates State when SectionList has finished rendering

I have a sectionlist with an ActivityIndicator at the footer. The ActivityIndicator doesn't go away even after the list has rendered every item. The data is local data.
I do know that I have to use React Hook, so I created _handleLoadMore() to update the state, but I don't know how to detect once the list has come to the end.
This is my code
import React, {useState, useEffect} from 'react';
import {
View,
Text,
StyleSheet,
SectionList,
ActivityIndicator,
} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
export default function TransactionHistoryList({data}: {data: any}) {
const [loadMore, setLoadMore] = useState('true')
const _handleLoadMore = () => {
//what to put here
}
const extractKey = ({
id,
}: {
id: any;
name: any;
accountNumber: any;
type: any;
amount: any;
}) => id;
const renderSeparator = () => {
return (
<View
style={{
height: 1,
width: '94%',
backgroundColor: '#000',
alignSelf: 'center',
}}
/>
);
};
const footerComponent = () => {
if (!_handleLoadMore) return null;
return (
<View
style={{
position: 'relative',
paddingVertical: 20,
borderTopWidth: 1,
marginTop: 10,
marginBottom: 10,
}}>
<ActivityIndicator
animating
size="small"
color="#CED0CE"
hidesWhenStopped={true}
/>
</View>
);
};
return (
<SafeAreaView>
<View style={styles.container}>
<Text style={styles.transactionhistory}>Transaction History</Text>
<SectionList
contentContainerStyle={{paddingBottom: 500}}
maxToRenderPerBatch={7}
onEndReachedThreshold={2}
updateCellsBatchingPeriod={4000}
ItemSeparatorComponent={renderSeparator}
sections={data}
renderSectionHeader={({section}) => {
return <Text style={styles.date}>{section.title}</Text>;
}}
renderItem={({item}) => {
return (
<View style={styles.item}>
<Text>
<View>
<Text style={styles.name}>{item.name}</Text>
<Text style={styles.accountNumber}>
{item.accountNumber}
</Text>
</View>
</Text>
<View style={styles.amountContainer}>
<Text
style={[
item.type == 'in' ? styles.moneyIn : styles.moneyOut,
]}>
{item.amount}
</Text>
</View>
</View>
);
}}
ListFooterComponent= {footerComponent}
keyExtractor={extractKey}
/>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
marginLeft: 20,
marginRight: 20,
marginTop: 120,
flex: -200,
//paddingBottom: 10
},
transactionhistory: {
fontWeight: 'bold',
fontSize: 18,
paddingBottom: 10,
paddingLeft: 25,
},
item: {
flexDirection: 'row',
justifyContent: 'space-between',
marginRight: 20,
marginLeft: 25,
paddingBottom: 10,
paddingTop: 10,
},
date: {
padding: 10,
marginBottom: 15,
backgroundColor: '#e0e0e0',
fontFamily: 'OpenSans-Bold',
fontSize: 15,
paddingLeft: 25,
},
name: {
fontSize: 14,
fontFamily: 'OpenSans-SemiBold',
},
accountNumber: {
fontSize: 12,
fontFamily: 'OpenSans-Regular',
},
amountContainer: {
paddingTop: 8,
},
moneyIn: {
color: '#689f38',
letterSpacing: 0.8,
fontSize: 16,
fontFamily: 'OpenSans-SemiBold',
},
moneyOut: {
color: '#b71c1c',
letterSpacing: 0.8,
fontSize: 16,
fontFamily: 'OpenSans-SemiBold',
},
loading: {
color: '#CED0CE',
},
});
section-list support on-scroll event and you can can hide/show activity-indicator feature quite smoothly with on scroll
Example:
const isCloseToBottom = ({layoutMeasurement, contentOffset, contentSize}) => {
const paddingToBottom = 20;
return layoutMeasurement.height + contentOffset.y >=
contentSize.height - paddingToBottom;
};
<SectionList
contentContainerStyle={{paddingBottom: 500}}
maxToRenderPerBatch={7}
onEndReachedThreshold={2}
onScroll={({nativeEvent}) => {
if (isCloseToBottom(nativeEvent)) {
if(!this.state.fetching_status){
//what you want to do when the screen reached end of screen
//console.log or something usefull
}
}
}}
.../>
I think it is possible to use onEndReached prop of SectionList in your case https://reactnative.dev/docs/sectionlist#onendreached
That is the correct place to write your logic to load next "page" of your items

React native search onChange input text, code structure

I am building a searchBar, whenever I do search I get undefined error because the value doesn't exist in state till I finish the whole value so I know that I will get error yet I am unable to solve it so I am trying to render cards according to the search input I think I did hard code my homeScreen I am not sure if I am doing it even right and here it comes the question to the three if statements inside render that I have is it good practice ? is it professional ? can i do something else which makes code easier to read and shorter ? I was thinking of eliminating the third if but I wasn't able to change state inside the second if so I had to add the toggle search function to let it work any ideas on how to eliminate the third if would be nice ..! thank you in advance guys
homeScreen.js
import axios from 'axios';
import React from 'react';
import {
ActivityIndicator,
ScrollView,
Text,
View,
TouchableOpacity,
TextInput,
} from 'react-native';
import Card from '../Components/Card/card';
export default class HomeScreen extends React.Component {
state = {
shows: [],
isLoading: true,
search: false,
title: '',
};
componentDidMount() {
this.getData();
}
toggleSearch = () => {
console.log('hlelleloe');
this.setState({
search: true,
});
};
getData = () => {
const requestUrls = Array.from({length: 9}).map(
(_, idx) => `http://api.tvmaze.com/shows/${idx + 1}`,
);
const handleResponse = data => {
this.setState({
isLoading: false,
shows: data,
});
};
const handleError = error => {
console.log(error);
this.setState({
isLoading: false,
});
};
Promise.all(requestUrls.map(url => axios.get(url)))
.then(handleResponse)
.catch(handleError);
};
render() {
const {isLoading, shows, search, title} = this.state;
if (isLoading) {
return <ActivityIndicator size="large" color="#0000ff" />;
} else if (!search) {
return (
<View>
<View>
<TouchableOpacity
onPress={this.toggleSearch}
style={{height: 300, width: 300}}>
<Text style={{textAlign: 'center', fontSize: 40}}>
Press to Search
</Text>
</TouchableOpacity>
</View>
<ScrollView style={{backgroundColor: '#E1E8E7'}}>
{shows.length &&
shows.map((show, index) => {
return (
<Card
key={show.data.id}
title={show.data.name}
rating={show.data.rating.average}
source={show.data.image.medium}
genres={show.data.genres}
language={show.data.language}
network={show.data.network}
schedule={show.data.schedule}
summary={show.data.summary}
navigation={this.props.navigation}
/>
);
})}
</ScrollView>
</View>
);
} else if (search) {
console.log(title);
return (
<View>
<TextInput
style={{
height: 100,
width: 100,
borderColor: 'gray',
borderWidth: 1,
}}
onChangeText={searchedTitle => (
<Card title={shows.data.searchedTitle} />
)}
/>
</View>
);
}
}
}
Card.js
import React from 'react';
import {
Image,
View,
Text,
Button,
StyleSheet,
TouchableOpacity,
} from 'react-native';
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp,
} from 'react-native-responsive-screen';
import Icon from 'react-native-vector-icons/FontAwesome';
const Card = props => {
return (
<View style={styles.container}>
<Image style={styles.Image} source={{uri: `${props.source}`}} />
<Text style={styles.title}>{props.title}</Text>
<View style={styles.ratingContainer}>
<Text style={styles.rating}>Rating: {props.rating}</Text>
<Icon name="star" size={30} color="grey" />
</View>
<TouchableOpacity
style={styles.button}
onPress={() => {
props.navigation.navigate('Details', {
title: props.title,
rating: props.rating,
source: props.source,
genres: props.genres,
language: props.language,
network: props.network,
schedule: props.schedule,
summary: props.summary,
});
}}>
<Text style={styles.buttonText}>Press for details </Text>
</TouchableOpacity>
</View>
);
};
export default Card;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
},
Image: {
flex: -1,
width: wp('90%'),
height: hp('65%'),
},
title: {
flex: 1,
fontSize: 40,
borderRadius: 10,
color: '#3C948B',
margin: 15,
justifyContent: 'center',
alignItems: 'center',
},
ratingContainer: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: 'white',
elevation: 6,
justifyContent: 'space-between',
borderWidth: 1,
width: 300,
},
rating: {
fontSize: 25,
paddingLeft: 15,
},
button: {
flex: 1,
color: '#3C948B',
backgroundColor: '#3C948B',
height: hp('7%'),
width: wp('70%'),
margin: 20,
alignItems: 'center',
borderBottomLeftRadius: 10,
borderTopRightRadius: 10,
},
buttonText: {
flex: 1,
fontSize: 25,
},
});
you Need to implement a constructor for your React component.
Typically, in React constructors are only used for two purposes:
Initializing local state by assigning an object to this.state
Binding event handler methods to an instance
Do
state = {
shows: [],
isLoading: true,
search: false,
title: '',
};
replace this with
constructor(props){
super(props);
this.state = {
shows: [],
isLoading: true,
search: false,
title: '',
};
}

How to update/ refresh the expandable list view in react native

I am developing an android app using react native which includes a cart page. I have used [ExpandableListView]:https://aboutreact.com/expandable-list-view/) to show the items grouped under categories. Each Item has a '+' and '-' button to change the count. Here is my code:
DetailScreen.js:
import React, { Component } from 'react';
import { LayoutAnimation, StyleSheet, TouchableOpacity, View, Text, ScrollView, UIManager, Platform, TextInput, KeyboardAvoidingView, ImageBackground, Picker, Image, Linking, Alert, } from 'react-native';
export default class DetailsScreen extends Component
{
static navigationOptions = {
title: 'Details',
header: null,
}
constructor(props)
{
super(props);
if (Platform.OS === 'android') {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
this.state =
{
listDataSource: [
{
isExpanded: false,
category_name: 'Item 1',
subcategory: [{ id: 1, val: 'Sub Cat 1', count:'0' }, { id: 3, val: 'Sub Cat 3', count:'0' }],
},
{
isExpanded: false,
category_name: 'Item 2',
subcategory: [{ id: 4, val: 'Sub Cat 4', count:'0' }, { id: 5, val: 'Sub Cat 5', count:'0' }],
}],
};
}
updateLayout = index => {
LayoutAnimation.configureNext
(LayoutAnimation.Presets.easeInEaseOut);
const array = [...this.state.listDataSource];
array[index]['isExpanded'] = !array[index]['isExpanded'];
this.setState(() => {
return {
listDataSource: array,
};
});
};
updateSalonData = newData =>
{
console.log('new Data: ' + JSON.stringify(newData));
var tempData = [...this.state.listDataSource];
let index = tempData.findIndex(x => x.category_name === newData.category_name);
tempData[index] = newData;
this.setState(() => {
return {
listDataSource: tempData,
};
});
};
render() {
return (
<View style={{ marginStart: 10, marginEnd: 10, marginTop: 5, borderBottomWidth: 0.5 }}></View>
<Text style={styles.topHeading}>Services</Text>
<ScrollView enabled keyboardShouldPersistTaps={'handled'} showsVerticalScrollIndicator={false} contentContainerStyle={{ flexGrow: 1, }}>
{this.state.listDataSource.map((item, key) => (
<ExpandableItemComponent
key={item.category_name}
onClickFunction={this.updateLayout.bind(this, key)}
item={item}
updateSalonData = {this.updateSalonData.bind(this, item)}/>
))}
</ScrollView>
</View>
);
}
}
ExpandableItemComponent.js:
import React, { Component } from 'react';
import { LayoutAnimation, StyleSheet, View, Text, ScrollView, UIManager, TouchableOpacity, Platform, } from 'react-native';
export default class ExpandableItemComponent extends Component {
//Custom Component for the Expandable List
constructor(props) {
super(props);
console.log('props: ' + JSON.stringify(props.item));
this.state = {
layoutHeight: 0,
dataSource:props.item,
};
}
componentWillReceiveProps(nextProps) {
console.log('componentWillReceiveProps');
if (nextProps.item.isExpanded) {
this.setState(() => {
return {
layoutHeight: null,
};
});
} else {
this.setState(() => {
return {
layoutHeight: 0,
};
});
}
console.log('next Item: ' + JSON.stringify(nextProps.item) + "\n");
this.setState(() => {
return {
dataSource: nextProps.item,
};
});
}
shouldComponentUpdate(nextProps, nextState) {
if (this.state.layoutHeight !== nextState.layoutHeight) {
return true;
}
return false;
}
setItemCount = (id) =>
{
const tempItem = this.props.item;
const data = this.props.item.subcategory;
const index = data.findIndex(x => x.id === id);
// console.log('pricing Index: ' + index);
if (index !== -1) {
data[index]["cartCount"] = 10;
tempItem.subcategory = data;
this.props.updateSalonData(tempItem);
}
}
render() {
return (
<View>
{/*Header of the Expandable List Item*/}
<TouchableOpacity
activeOpacity={0.8}
onPress={this.props.onClickFunction}
style={styles.header}>
<Text style={styles.headerText}>{this.state.dataSource.category_name}</Text>
</TouchableOpacity>
<View
style={{
height: this.state.layoutHeight,
overflow: 'hidden',
}}>
{/*Content under the header of the Expandable List Item*/}
{this.state.dataSource.subcategory.map((item, key) => (
<TouchableOpacity
key={key}
style={styles.content}
onPress={() => alert('Id: ' + item.id + ' val: ' + item.val)}>
<View style={{ flex: 1, flexDirection: 'row', alignContent: 'center', justifyContent: 'space-between'}}>
<Text style={styles.text}>{item.val}</Text>
<View style={{ flexDirection: 'row', alignSelf: 'center', }}>
<Text style={styles.text}>{item.val}</Text>
<View style={{ height: 25, width: 75, flexDirection: 'row', borderRadius: 15, borderWidth: 1, alignSelf: 'center', justifyContent: 'space-evenly', borderColor: 'orange', overflow: 'hidden' }}>
<View style={{ alignContent: 'center', justifyContent: 'center' }}>
<Text onPress={()=>{this.setItemCount(item.id)}} style={{ width: 25, height: 25, fontSize: 12, color: 'orange', fontWeight: 'bold', textAlign: 'center', textAlignVertical: 'center' }}>+</Text>
</View>
<View style={{ borderWidth: 1, borderColor: 'orange', backgroundColor: 'orange', alignContent: 'center', justifyContent: 'center' }}>
<Text style={{ width: 25, height: 25, fontSize: 12, color: 'white', fontWeight: 'bold', textAlign: 'center', textAlignVertical: 'center' }}>{item.cartCount}</Text>
</View>
<View style={{ alignContent: 'center', justifyContent: 'center' }}>
<Text style={{ width: 25, height: 25, fontSize: 12, color: 'orange', fontWeight: 'bold', textAlign: 'center', textAlignVertical: 'center' }}>-</Text>
</View>
</View>
</View>
</View>
{/* <View style={styles.separator} /> */}
</TouchableOpacity>
))}
</View>
<View style={styles.separator} />
</View>
);
}
}
Now the problem is, When i click '+' button the count is actually incremented in the code but its not been updated in the UI. But when I collapse and expand the same item, now the value is updated. Someone Pls guide me to update the count once I click the + button.
Can you replace your this.state.dataSource to direct this.props.updateSalonData on ExpandableItemComponent.js
If an update was done in the parent class it will automatically update in child class if so do.
eg:
...
{this.props.updateSalonData.subcategory.map((item, key) => (
....
like this.

Change color after click on TouchableHighlight in react native

I have done a many research on the color change after press/click. Finally
I got this script for change the state and put it in the TouchableHighlight. But When i clicked on that, only the "underlayColor={'gray'}" is working. Can i get some idea ?
here is my code
import React, { Component } from 'react';
import {
StyleSheet,
Text,
StatusBar ,
TouchableOpacity,
View,
FlatList,
ActivityIndicator,
TouchableHighlight,
PropTypes,
Image,
Alert
} from 'react-native';
import Logo from '../components/Logo';
import Form from '../components/Front';
import {Actions} from 'react-native-router-flux';
export default class Login extends Component<{}> {
constructor() {
super();
this.state = {
dataSource: {},
pressed: false
};
}
izijackpotconfirm() {
Actions.izijackpotconfirm()
}
componentDidMount() {
var that = this;
let items = Array.apply(null, Array(25)).map((v, i) => {
return { id: i+1 };
});
that.setState({
dataSource: items,
});
}
static navigationOptions = {
title: "Izi Jackpot",
headerStyle: {
backgroundColor: "#354247"
},
headerTintColor: "#fff",
headerTitleStyle: {
fontWeight: "bold"
}
};
render() {
var jackpotNumbers = [];
let btn_class = this.state.black ? "NormalSet" : "SelectedSet";
return(
<View style={styles.container}>
<View style={styles.middlecontainer}>
<Text style={styles.logoText}>Please Select 5 Numbers and Submit</Text>
</View>
<FlatList
data={this.state.dataSource}
renderItem={({ item }) => (
<View style={{ flex: 1, flexDirection: 'column', margin: 1 }}>
<TouchableHighlight
onPress={() => { Alert.alert(this.state.pressed) }}
style={[
styles.iziPizi,
this.state.pressed ? { backgroundColor: "blue" } : {}
]}
onHideUnderlay={() => {
this.setState({ pressed: false });
}}
onShowUnderlay={() => {
this.setState({ pressed: true });
}}
underlayColor={'gray'}
>
<Text style={styles.buttonText}>{ item.id}</Text></TouchableHighlight>
</View>
)}
//Setting the number of column
numColumns={5}
keyExtractor={(item, index) => index}
/>
<View style={styles.middlecontainer}>
<TouchableOpacity style={styles.button} onPress={this.izijackpotconfirm} >
<Text style={styles.buttonText}>Submit</Text>
</TouchableOpacity>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container : {
backgroundColor:'#6F9000',
justifyContent: 'center',
flex: 1,
paddingTop: 30,
},
middlecontainer: {
textAlign: 'center',
alignItems: 'center',
justifyContent :'center',
flex:1
},
signupTextCont : {
flexGrow: 1,
alignItems:'flex-end',
justifyContent :'center',
paddingVertical:16,
flexDirection:'row'
},
signupText: {
color:'rgba(255,255,255,0.6)',
fontSize:16
},
signupButton: {
color:'#ffffff',
fontSize:16,
fontWeight:'500'
},
iziPizi: {
width: 55,
padding: 15,
margin: 5,
borderRadius: 80,
borderWidth: 2,
borderColor: '#FFFFFF',
flex:1
},
iziPiziPress: {
width: 55,
padding: 15,
margin: 5,
backgroundColor:'#1c313a',
borderRadius: 80,
borderWidth: 2,
borderColor: '#FFFFFF',
flex:1
},
button: {
width:300,
backgroundColor:'#1c313a',
borderRadius: 25,
marginVertical: 10,
paddingVertical: 13
},
buttonText: {
fontSize:16,
fontWeight:'500',
color:'#ffffff',
textAlign:'center'
},
logoText : {
color:'#FFFFFF',
fontSize: 16,
fontWeight: '500',
alignItems: 'center',
justifyContent:'center',
},
imageThumbnail: {
justifyContent: 'center',
alignItems: 'center',
height: 100,
},
});
One more thing to say that, i have used FlatList here. Please help on this. Thanks in advance.
The problem is in how you work with the styles inside the Touchable. My advice is to create 2 styles that contain the changes:
style={
this.state.pressed ? styles.pressed : styles.iziPizi
}
Inside the touchable of course:
<TouchableHighlight
onPress={() => { Alert.alert(this.state.pressed) }}
style={
this.state.pressed ? styles.pressed : styles.iziPizi
}
onHideUnderlay={() => {
this.setState({ pressed: false });
}}
onShowUnderlay={() => {
this.setState({ pressed: true });
}}
underlayColor={'gray'}
>
yes. there was a problem in FlatList. but i dont know what is its problem.
use ListItem of native-base instead.
remember that if you want to use ListItem, in constructor change
this.state = {
dataSource: {},
...
}
to
this.state = {
dataSource: [],
}
use array insead. here is a sample code for you.
<View style={{ flex: 1, flexDirection: 'column', margin: 1 }}>
<List>
{this.state.dataSource.map( item =>
<ListItem>
<TouchableHighlight
onPress={() => {}}
onShowUnderlay={this.onPress.bind(this)}
>
<Text style={styles.buttonText}>{ item.id}</Text>
</TouchableHighlight>
</ListItem> )
}
</List>
</View>
Also define onPress method.
another problem in your code is this that you setState of pressed.
it results that all of your element style will be changed. so all of your button backgroundColor will be changed.
so you must define pressed flag for every element in your array and change this flag

React Native Display Saved Data When The App Opens

I have some problems with AsyncStorage and i was hoping that you can help me out. I have to write some notes and save them so when I open the app again, they will be displayed on a ListView.
Here are the classes I used:
Notes.js:
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
} from 'react-native';
export default class Note extends Component {
render() {
return (
<View key={this.props.keyval} style={styles.note}>
<Text style={styles.noteText}>{this.props.val.date}</Text>
<Text style={styles.noteText}>{this.props.val.note}</Text>
<TouchableOpacity onPress={this.props.deleteMethod} style={styles.noteDelete}>
<Text style={styles.noteDeleteText}>Del</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
note: {
position: 'relative',
padding: 20,
paddingRight: 100,
borderBottomWidth:2,
borderBottomColor: '#ededed'
},
noteText: {
paddingLeft: 20,
borderLeftWidth: 10,
borderLeftColor: '#0000FF'
},
noteDelete: {
position: 'absolute',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#2980b9',
padding: 10,
top: 10,
bottom: 10,
right: 10
},
noteDeleteText: {
color: 'white'
}
});
This is the component that I use every time when I want to create a note.
Main.js:
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
TextInput,
ScrollView,
TouchableOpacity,
AsyncStorage,
} from 'react-native';
import Note from './Note';
export default class Main extends Component {
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: '',
};
this.getSavedNotes(this.state.noteArray);
}
render() {
let notes = this.state.noteArray.map((val, key)=>{
return <Note key={key} keyval={key} val={val}
deleteMethod={()=>this.deleteNote(key)}/>
});
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}>- NOTER -</Text>
</View>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<View style={styles.footer}>
<TextInput
style={styles.textInput}
placeholder='Write your note here'
onChangeText={(noteText)=> this.setState({noteText})}
value={this.state.noteText}
placeholderTextColor='white'
underlineColorAndroid='transparent'>
</TextInput>
</View>
<TouchableOpacity onPress={ this.addNote.bind(this) } style={styles.addButton}>
<Text style={styles.addButtonText}>+</Text>
</TouchableOpacity>
</View>
);
}
addNote(){
if(this.state.noteText){
var d = new Date();
this.state.noteArray.push({
'date':d.getFullYear()+
"/"+(d.getMonth()+1) +
"/"+ d.getDate(),
'note': this.state.noteText
});
this.setState({ noteArray: this.state.noteArray });
this.setState({noteText:''});
AsyncStorage.setItem('arr', JSON.stringify(this.state.noteArray));
alert(this.state.noteArray);
}
}
deleteNote(key){
this.state.noteArray.splice(key, 1);
this.setState({noteArray: this.state.noteArray});
}
getSavedNotes = async (noteArray) =>{
try{
let data = await AsyncStorage.getItem('arr');
if(JSON.parse(data))
{
this.state.noteArray = JSON.parse(data);v
}
}catch(error){
alert(error);
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
header: {
backgroundColor: '#1A237E',
alignItems: 'center',
justifyContent:'center',
borderBottomWidth: 10,
borderBottomColor: '#ddd'
},
headerText: {
color: 'white',
fontSize: 18,
padding: 26
},
scrollContainer: {
flex: 1,
marginBottom: 100
},
footer: {
position: 'absolute',
bottom: 0,
backgroundColor: '#000000',
left: 0,
right: 70,
zIndex: 10
},
textInput: {
alignSelf: 'stretch',
color: '#fff',
padding: 20,
backgroundColor: '#252525',
borderTopWidth:2,
borderTopColor: '#ededed'
},
addButton: {
position: 'absolute',
zIndex: 11,
right: 0,
bottom: 0,
backgroundColor: '#1A237E',
width: 70,
height: 68,
// borderRadius: 35,
alignItems: 'center',
justifyContent: 'center',
elevation: 8
},
addButtonText: {
color: '#fff',
fontSize: 24
}
});
Here is where I try to save the notes. It seems like the notes are saved but they are not displayed as I open the app. They are displayed only after I tape a letter in the text box.
Finally the App.js:
import React, { Component } from 'react';
import Main from './app/components/Main.js';
export default class App extends Component {
render() {
return (
<Main/>
);
}
}
Here I just display the Main.js component.
getSavedNotes = async (noteArray) =>{
try{
let data = await AsyncStorage.getItem('arr');
data = JSON.parse(data);
this.setState({noteArray:data}) //assuming data as array of notes
}catch(error){
alert(error);
}
}