React Native : State value is evaluated as undefined - reactjs

In my Logitem component I have a Modal which is invoked upon clicking on a Text element.
This part is working fine and I am able to handle the click event successfully.
But for some reason within the event handler method deleteSelectedRecord(), the state value is returned as 'undefined' for this.state.selecteddate
I have marked the line where the evaluation happens as Line X
This is my code
import React, { Component } from 'react';
import { Text, View, Modal, DatePickerIOS, TextInput, Button } from 'react-native';
import {
deleteSelectedRecordDB
} from '../src/helper';
import { Spinner } from '../src/Spinner';
export default class Logitem extends Component {
constructor(props) {
super(props);
const { logstringdate, bmi, weight, logdate } = this.props;
}
state = {
selecteddate: '1',
selectedweight: this.props.weight,
showmodal: false,
date: new Date(86400000 * this.props.logdate),
}
async deleteSelectedRecord(){
console.log('Delete clicked');
console.log('this.state.selecteddate ==>' + this.state.selecteddate); //LINE X
const result = await deleteSelectedRecordDB(this.props.logdate);
console.log('deleteSelectedRecord after');
console.log('result ==> '+ result);
return result;
}
setModalVisible = (visible) => {
this.setState({showmodal: visible});
}
onWeightClick = () => {
this.setState({ selecteddate: this.props.logdate, showmodal: true }, () => {
console.log('Value in props==>' + this.props.logdate);
console.log('The selecteddate in the state ==> ' + this.state.selecteddate);
});
}
onDateChange(date) {
this.setState({
date: date
});
}
render() {
return (
<View style={styles.containerStyle}>
<Modal
animationType="slide"
transparent={false}
visible={this.state.showmodal}
onRequestClose={() => {alert("Modal has been closed.")}}
>
<View style={{marginTop: 22}}>
<DatePickerIOS
date={this.state.date}
mode="date"
onDateChange={(date) => this.onDateChange(date)}
style={{ height: 100, width: 300 }}
/>
</View>
<View style={{ marginTop: 22, borderColor: '#ddd', borderWidth: 5 }}>
<TextInput
returnKeyType="done"
keyboardType='numeric'
style={{
height: 40,
width: 60,
borderColor: 'gray',
borderWidth: 1,
}}
onChangeText={(text) => this.setState({ selectedweight: text })}
value={this.state.selectedweight.toString()}
/>
<Text>KG</Text>
<Button
title="Delete"
onPress={this.deleteSelectedRecord}
style={{ marginTop: 200 }}
/>
</View>
</Modal>
<View style={styles.headerContentStyle}>
<Text>{this.props.logstringdate}</Text>
<Text>{this.props.bmi}</Text>
</View>
<View style={styles.thumbnailContainerStyle}>
<Text onPress={this.onWeightClick}>{this.props.weight}</Text>
</View>
</View>
);
}
};
const styles = {
containerStyle: {
borderWidth: 1,
borderRadius: 2,
borderColor: '#ddd',
borderBottomWidth: 0,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2},
shadowOpacity: 0.1,
shadowRadius: 2,
elevation: 1,
marginLeft: 5,
marginRight: 5,
marginTop:10,
},
thumbnailContainerStyle: {
justifyContent: 'center',
alignItems: 'center',
marginLeft: 10,
marginRight: 10,
flexDirection: 'row'
},
headerContentStyle: {
flexDirection: 'column',
justifyContent: 'space-around'
},
};
This is my output
As can be seen from the console output the state value of selecteddate is not undefined.
Can someone take a look and let me know what is wrong with the code ?

Try this code in <Button> which invokes deleteSelectedRecord method:
<Button
title="Delete"
onPress={this.deleteSelectedRecord.bind(this)}
style={{ marginTop: 200 }}
/>

You need to bind deleteSelectedRecord to this somewhere in your constructor:
this.deleteSelectedRecord = this.deleteSelectedRecord.bind(this)

Related

React Native Error: Element type is invalid (Formik)

I have a problem with Login Screen I am using Formik to use custom TextInputs but I am getting this error: (Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.)
This is my LoginScreen.js
import React, {useState} from 'react';
import { Alert,
Image,
KeyboardAvoidingView,
ScrollView,
StyleSheet,
TouchableOpacity,
View,
} from 'react-native';
import AppText from '../../components/AppText';
import AppButton from '../../components/AppButton';
import colors from '../../configs/colors';
import AppInput from '../../components/AppInput';
import {Formik} from 'formik';
import * as Yup from 'yup';
import http from '../../services/http';
import storage from '../../services/storage';
import {setUser} from '../../store/reducers/auth';
import {CommonActions} from '#react-navigation/native';
import {useDispatch} from 'react-redux';
import ProgressDialog from 'react-native-progress-dialog';
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
const LoginScreen = ({navigation}) => {
const dispatch = useDispatch();
const [loading, setLoading] = useState(false);
const loginUser = async values => {
try {
setLoading(true);
values['role'] = 2;
values['device_token'] ='XYZ';
const res = await http.post({
url: '/user/login',
body: values,
});
console.log('Res => ', res.data);
if (res.data.records.isVerified === 1) {
dispatch(setUser(res.data));
http.setUserTokenAndId(
res.data.records.accessToken,
res.data.records.id,
);
await storage.store('USER', res.data);
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [{name: 'Home'}],
}),
);
} else {
Alert.alert('Error', res.data.message, [
{
text: 'Resend Email',
onPress: () => {
resendEmail(res.data.records.accessToken);
},
style: 'destructive',
},
{
text: 'Cancel',
onPress: () => {},
style: 'cancel',
},
]);
}
} catch (err) {
console.log('Err => ', err);
} finally {
setLoading(false);
}
};
const resendEmail = async token => {
try {
setLoading(true);
const res = await http.post({
url: '/email/verification-notification',
body: {},
headers: {Authorization: 'Bearer ' + token},
});
Alert.alert('Success', res.data.message);
} catch (err) {
console.log('Err', err);
} finally {
setLoading(false);
}
};
return (
<View style={styles.container}>
<View style={styles.cardContainer}>
<View style={styles.card}>
<View>
<KeyboardAwareScrollView style={{height: '100%'}}>
<>
<Image source={require('../../assets/header.png')} />
<AppText style={styles.headingText}>Sign In To Forsa</AppText>
<AppText style={styles.subHeadingText}>
Welcome Back! sign in to your previous account to continue the
shoping
</AppText>
</>
<View>
<Formik
initialValues={{email: '', password: ''}}
validationSchema={Yup.object({
email: Yup.string().label('Email').required(),
password: Yup.string().label('Password').min(5).required(),
})}
onSubmit={loginUser}>
{({submitForm}) => {
return (
<View>
<Image
style={{
alignItems: 'center',
marginTop: 10,
height: 150,
width: '100%',
}}
resizeMode="contain"
source={require('../../assets/loginicon.png')}
/>
<View style={{marginHorizontal: 20}}>
<AppInput
label=""
placeholder="Email*"
keyboardType="email-address"
name="email"
iconName="email"
autoComplete={true}
inputStyle={styles.input}
inputWrapperStyle={styles.inputWrapper}
/>
<AppInput
label=""
placeholder="Password*"
name="password"
secureTextEntry={true}
iconName="lock"
inputWrapperStyle={styles.inputWrapper}
inputStyle={styles.input}
/>
</View>
<AppButton
containerStyle={styles.loginBtn}
onPress={submitForm}
title={'Login'}></AppButton>
<View
style={{
justifyContent: 'space-between',
flexDirection: 'row',
marginTop: 10,
}}>
<View />
<AppText
style={{
color: colors.TAB_BAR_GREY,
fontSize: 13,
marginRight: 25,
}}
onPress={() =>
navigation.navigate('forgotPassword')
}>
Forgot Password?
</AppText>
</View>
<View
style={{
justifyContent: 'center',
flexDirection: 'row',
marginTop: 10,
}}>
<AppText>Don't have any account yet?</AppText>
<TouchableOpacity
onPress={() =>
navigation.navigate('CreateAccount')
}>
<AppText
style={{
marginLeft: 10,
color: colors.PRIMARY_GREEN,
}}>
Sign Up
</AppText>
</TouchableOpacity>
</View>
</View>
);
}}
</Formik>
</View>
</KeyboardAwareScrollView>
</View>
{loading && (
<ProgressDialog
loaderColor={colors.PRIMARY_GREEN}
visible={loading}
labelStyle={{marginTop: 10}}
/>
)}
</View>
</View>
</View>
);
};
export default LoginScreen;
const styles = StyleSheet.create({
headingText: {
fontSize: 30,
position: 'absolute',
marginTop: 80,
marginLeft: 20,
color: colors.WHITE,
fontWeight: '600',
},
subHeadingText: {
fontSize: 18,
position: 'absolute',
marginTop: 120,
marginLeft: 20,
color: colors.WHITE,
fontWeight: '400',
},
loginBtn: {
marginTop: 20,
borderRadius: 50,
marginHorizontal: 20,
},
input: {
paddingLeft: 10,
},
inputWrapper: {
borderWidth: 0.5,
borderRadius: 50,
},
label: {
color: colors.PRIMARY_GREEN,
},
loading: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center',
// backgroundColor: "rgba(66,66,66,0.47)",
},
btnText: {
color: colors.WHITE,
fontSize: 16,
},
});
This is my AppInput.js (Which is custom TextInput):
import React from 'react';
import {View, TextInput, StyleSheet, Platform} from 'react-native';
import AppText from './AppText';
import {useFormikContext} from 'formik';
import colors from '../configs/colors';
import {MaterialCommunityIcons} from 'react-native-vector-
icons/MaterialCommunityIcons';
export default props => {
const {
name,
label,
labelStyle,
inputWrapperStyle,
inputWrapperErrorStyle,
inputStyle,
errorStyle,
containerStyle,
iconName,
value,
multiline = false,
editable = true,
} = props;
const {values, errors, touched, setFieldValue} = useFormikContext();
let wrapperErrorStyle = error
? {
borderWidth: 1,
borderColor: colors.ERROR_TEXT,
...inputWrapperErrorStyle,
}
: {
// borderWidth: 1,
// borderColor: props.value ? colors.LIGHT_GREY : colors.LIGHT_GREY,
...inputWrapperErrorStyle,
};
const error = touched[name] && errors[name];
let iconColor = props.value ? colors.PRIMARY_GREEN : colors.TAB_BAR_GREY;
if (error) iconColor = colors.errorText;
return (
<View style={[styles.containerStyle, containerStyle]}>
<AppText style={[styles.label, labelStyle]}>{label}</AppText>
<View style={[styles.inputWrapper, inputWrapperStyle, wrapperErrorStyle]}>
{iconName && (
<MaterialCommunityIcons
name={iconName}
size={25}
style={styles.iconStyles}
color={iconColor}
/>
)}
<TextInput
{...props}
value={value}
editable={editable}
onChangeText={txt => {
setFieldValue(name, txt);
}}
multiline={multiline}
placeholderTextColor={colors.TAB_BAR_GREY}
style={[styles.input, inputStyle]}
/>
</View>
{error ? (
<AppText style={[styles.error, errorStyle]}>{error}</AppText>
) : null}
</View>
);
};
const styles = StyleSheet.create({
containerStyle: {
marginTop: Platform.OS === 'ios' ? 5 : 0,
marginBottom: 0,
},
label: {
fontSize: 15,
},
inputWrapper: {
flexDirection: 'row',
borderWidth: 0,
},
iconStyles: {
justifyContent: 'center',
alignItems: 'center',
marginTop: 7,
marginLeft: 18,
},
input: {
flex: 1,
minHeight: 40,
maxHeight: 150,
fontSize: 16,
color: colors.BLACK,
},
error: {
color: colors.ERROR_TEXT,
marginTop: 3,
fontSize: 16,
},
});
I am searching from 3-4 hours but couldn't find any solution to this, I am kinda new to react native. Any help will be appreciated. Thank you.

How to select only one item from a flatlist in React and change it's style?

I'm stuck with trying to make a flatlist work with one selection and change only it's background. I already got the id from the pressed item and I'm passing the information to another page. But after clicking, it's style is not changing. I need to select just one and if I click on another it should deselect the first one and keep the new one selected.
My code is as folows:
import React, { Component } from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity, FlatList, Linking, ActivityIndicator } from 'react-native';
import { Searchbar } from 'react-native-paper';
export default class Merchants extends Component {
constructor() {
super()
this.state = {
search: '',
loading: false,
merchantObj: [],
btnDisabled: true,
itemId: null,
imgLink: null,
listClicked: false,
}
this.arrayholder = [];
}
componentDidMount() {
const merchantUrl = 'http://165.227.43.115:8080/merchant/merchant'
fetch(merchantUrl)
.then(response => response.json())
.then(data => {
this.setState({ merchantObj: data, loading: false },
function () {
this.arrayholder = data;
})
})
.catch(error => {
console.log(error)
});
}
search = text => {
console.log(text);
};
clear = () => {
this.search.clear();
};
SearchFilterFunction(text) {
//passing the inserted text in textinput
const newData = this.arrayholder.filter(function (item) {
//applying filter for the inserted text in search bar
const itemData = item.name ? item.name.toUpperCase() : ''.toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
this.setState({
//setting the filtered newData on datasource
//After setting the data it will automatically re-render the view
merchantObj: newData,
search: text,
});
}
FlatListItemSeparator = () => {
return (
<View
style={{
height: 1,
width: "95%",
justifyContent: 'center',
backgroundColor: "#DCDCDC",
}}
/>
);
}
MerchSelected = (selectedId) => {
if (this.state.btnDisabled === true) {
return (
<View style={styles.btnDsb}>
<Text style={styles.txtBtn}>Select</Text>
</View>
)
} else {
return (
<TouchableOpacity onPress={(item) => this.props.navigation.navigate('Main', { itemId: this.state.itemId, itemImg: this.state.imgLink })}>
<View style={styles.btnSelect}>
<Text style={styles.txtBtn}>Select</Text>
</View>
</TouchableOpacity>
)
}
}
PressedItem = (itemId, itemImg) => {
console.log(itemId)
this.setState({ itemId: itemId, btnDisabled: false, imgLink: itemImg })
}
renderItem = ({ item }) => {
return (
<TouchableOpacity onPress={() => this.PressedItem(item.id, item.image)} >
<View style={styles.listItem} >
<Image
style={{ width: 80, height: 80 }}
source={{ uri: `${item.image}` }} />
<View style={{ flexDirection: 'column', marginLeft: 2 }}>
< Text style={{ fontWeight: 'bold', fontSize: 20 }} > {item.name} </Text>
{item.shoppingOption == 'STORE' ? <Text>Store</Text> : <Text>In-Store & Online</Text>}
<Text>${item.minAmount} - ${item.maxAmount}</Text>
<Text style={{ color: '#00CED1' }}
onPress={() => Linking.openURL(`${item.website}`)}>
view website
</Text>
</View>
</View>
</TouchableOpacity>
)
}
render() {
if (this.state.loading) {
return (
<View>
<Text>Loading...</Text>
</View>
);
}
return (
<View style={styles.container} >
<View style={styles.searchBar}>
<Searchbar
round
placeholder="Search"
onChangeText={text => this.SearchFilterFunction(text)}
onClear={text => this.SearchFilterFunction('')}
value={this.state.search}
/>
</View>
<View style={styles.merchantsList}>
<FlatList
data={this.state.merchantObj}
renderItem={this.renderItem}
ItemSeparatorComponent={this.FlatListItemSeparator}
keyExtractor={item => item.id.toString()}
extraData={this.state}
>
</FlatList>
</View>
<View style={styles.footerBtn}>
<TouchableOpacity onPress={() => this.props.navigation.navigate('Main', { itemId: undefined })}>
<View style={styles.btnSelect}>
<Text style={styles.txtBtn}>Cancel</Text>
</View>
</TouchableOpacity>
{this.state.btnDisabled === true ? this.MerchSelected('Sim') : this.MerchSelected('Nao')}
</View>
</View >
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f2f2f4',
alignItems: 'center',
},
searchBar: {
flex: 1,
top: '5%',
width: '90%',
backgroundColor: 'rgba(242, 242, 244,0.5)'
},
merchantsList: {
flex: 6,
width: '95%',
},
footerBtn: {
flex: 1,
width: '100%',
},
listItem: {
flexDirection: 'row',
marginTop: 5,
},
notSelected: {
backgroundColor: '#f2f2f4'
},
listItemSlc: {
backgroundColor: '#48D1CC',
},
btnSelect: {
justifyContent: 'center',
width: '95%',
borderRadius: 5,
borderColor: '#00CED1',
borderStyle: 'solid',
borderWidth: 2,
height: 40,
marginTop: 5,
marginLeft: 8,
},
btnDsb: {
justifyContent: 'center',
width: '95%',
borderRadius: 5,
backgroundColor: 'gray',
height: 40,
marginTop: 5,
marginLeft: 8,
},
txtBtn: {
textAlign: 'center',
color: '#00CED1',
fontSize: 20,
},
})
import React, { Component } from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity, FlatList, Linking, ActivityIndicator } from 'react-native';
import { Searchbar } from 'react-native-paper';
export default class Merchants extends Component {
constructor() {
super()
this.state = {
search: '',
loading: false,
merchantObj: [],
btnDisabled: true,
itemId: null,
imgLink: null,
listClicked: false,
itemindex:"",
}
this.arrayholder = [];
}
componentDidMount() {
const merchantUrl = 'http://165.227.43.115:8080/merchant/merchant'
fetch(merchantUrl)
.then(response => response.json())
.then(data => {
//var l_Data = [];
//for (var l_index = 0; l_index < data.length; l_index++)
//{
// l_Data[l_index] = {
// }
//}
this.setState({ merchantObj: data, loading: false },
function () {
this.arrayholder = data;
})
})
.catch(error => {
console.log(error)
});
}
search = text => {
console.log(text);
};
clear = () => {
this.search.clear();
};
SearchFilterFunction(text) {
//passing the inserted text in textinput
const newData = this.arrayholder.filter(function (item) {
//applying filter for the inserted text in search bar
const itemData = item.name ? item.name.toUpperCase() : ''.toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
this.setState({
//setting the filtered newData on datasource
//After setting the data it will automatically re-render the view
merchantObj: newData,
search: text,
});
}
FlatListItemSeparator = () => {
return (
<View
style={{
height: 1,
width: "95%",
justifyContent: 'center',
backgroundColor: "#DCDCDC",
}}
/>
);
}
MerchSelected = (selectedId) => {
if (this.state.btnDisabled === true) {
return (
<View style={styles.btnDsb}>
<Text style={styles.txtBtn}>Select</Text>
</View>
)
} else {
return (
<TouchableOpacity onPress={(item) => this.props.navigation.navigate('Main', { itemId: this.state.itemId, itemImg: this.state.imgLink })}>
<View style={styles.btnSelect}>
<Text style={styles.txtBtn}>Select</Text>
</View>
</TouchableOpacity>
)
}
}
PressedItem = (itemId, itemImg) => {
console.log(itemId)
this.setState({ itemId: itemId, btnDisabled: false, imgLink: itemImg })
}
renderItem = ({ item }) => {
return (
<TouchableOpacity onPress={() => { this.PressedItem(item.id, item.image), this.setState({ itemindex: item.id }) }} >
<View style={this.state.itemindex == item.id ? styles.SelectedlistItem : styles.listItem} >
<Image
style={{ width: 80, height: 80 }}
source={{ uri: `${item.image}` }} />
<View style={{ flexDirection: 'column', marginLeft: 2 }}>
< Text style={{ fontWeight: 'bold', fontSize: 20 }} > {item.name} </Text>
{item.shoppingOption == 'STORE' ? <Text>Store</Text> : <Text>In-Store & Online</Text>}
<Text>${item.minAmount} - ${item.maxAmount}</Text>
<Text style={{ color: '#00CED1' }}
onPress={() => Linking.openURL(`${item.website}`)}>
view website
</Text>
</View>
</View>
</TouchableOpacity>
)
}
render() {
if (this.state.loading) {
return (
<View>
<Text>Loading...</Text>
</View>
);
}
return (
<View style={styles.container} >
<View style={styles.searchBar}>
<Searchbar
round
placeholder="Search"
onChangeText={text => this.SearchFilterFunction(text)}
onClear={text => this.SearchFilterFunction('')}
value={this.state.search}
/>
</View>
<View style={styles.merchantsList}>
<FlatList
data={this.state.merchantObj}
renderItem={this.renderItem}
ItemSeparatorComponent={this.FlatListItemSeparator}
keyExtractor={item => item.id.toString()}
extraData={this.state}
/>
</View>
<View style={styles.footerBtn}>
<TouchableOpacity onPress={() => this.props.navigation.navigate('Main', { itemId: undefined })}>
<View style={styles.btnSelect}>
<Text style={styles.txtBtn}>Cancel</Text>
</View>
</TouchableOpacity>
{this.state.btnDisabled === true ? this.MerchSelected('Sim') : this.MerchSelected('Nao')}
</View>
</View >
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f2f2f4',
alignItems: 'center',
},
searchBar: {
flex: 1,
top: '5%',
width: '90%',
backgroundColor: 'rgba(242, 242, 244,0.5)'
},
merchantsList: {
flex: 6,
width: '95%',
},
footerBtn: {
flex: 1,
width: '100%',
},
listItem: {
flexDirection: 'row',
marginTop: 5,
},
SelectedlistItem: {
flexDirection: 'row',
marginTop: 5,
backgroundColor:"grey",
},
btnSelect: {
justifyContent: 'center',
width: '95%',
borderRadius: 5,
borderColor: '#00CED1',
borderStyle: 'solid',
borderWidth: 2,
height: 40,
marginTop: 5,
marginLeft: 8,
},
btnDsb: {
justifyContent: 'center',
width: '95%',
borderRadius: 5,
backgroundColor: 'gray',
height: 40,
marginTop: 5,
marginLeft: 8,
},
txtBtn: {
textAlign: 'center',
color: '#00CED1',
fontSize: 20,
},
})
above is code that's you want and the screenshot is here
Since you keep track of the selected itemId, you can simply override the style of selected item as below.
<TouchableOpacity onPress={() => this.PressedItem(item.id, item.image)} >
{/* Suppeose you want to change the background color of selected item as 'red' */}
<View style={item.id !== this.state.itemId ? styles.listItem : [styles.listItem, { backgroundColor: 'red' }]}>
...
</View>
</TouchableOpacity>
But you need to add extraData property in FlatList for telling the list to re-render.
extraData={this.state.itemId}
Hope this helps you. Feel free for doubts.

push button key value to array

I have a TouchableOpacity with key="red" and another one with key="black" and everytime a button is pushed the value should be added to the array. I've searched the internet for about one hour to find a way of doing this and I can't find nothing
import React from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
var RedBlackArray = [ "Red", "Black", "Red"];
export default class App extends React.Component {
constructor() {
super();
this.state = {
countRed: 0,
countBlack: 0
};
}
handlePressRed = () => {
this.setState(prevState => ({ countRed: prevState.countRed + 1 }));
}
handlePressBlack = () => {
this.setState(prevState => ({ countBlack: prevState.countBlack + 1 }));
}
render() {
return (
<View>
<View style={styles.container}>
<View style={styles.col1}>
<Text>red: {this.state.countRed}</Text>
<TouchableOpacity key='red' onPress={this.handlePressRed}>
<Text style={styles.button}>red!</Text>
</TouchableOpacity>
</View>
<View style={styles.col2}>
<Text>black: {this.state.countBlack}</Text>
<TouchableOpacity key='black' onPress={this.handlePressBlack}>
<Text style={styles.button.buton2}>black!</Text>
</TouchableOpacity>
</View>
</View>
<View style={{marginTop: 30, paddingLeft: 20, paddingRight:20}}>
<Text>So far the order has been:</Text>
{RedBlackArray.map((item, key)=> (
<Text key={key}>{item}</Text>
))}
</View>
</View>
);
}
}
const styles = StyleSheet.create({
button: {
marginTop: 50,
backgroundColor: 'red',
borderColor: 'white',
borderWidth: 1,
borderRadius: 12,
color: 'white',
fontSize: 20,
fontWeight: 'bold',
overflow: 'hidden',
padding: 12,
textAlign:'center',
buton2: {
marginTop: 50,
backgroundColor: 'black',
borderColor: 'white',
borderWidth: 1,
borderRadius: 12,
color: 'white',
fontSize: 20,
fontWeight: 'bold',
overflow: 'hidden',
padding: 12,
textAlign:'center'
}
},
container: {
flexDirection: 'row',
justifyContent: 'center'
},
col1: {
paddingTop: 50,
paddingRight: 30,
justifyContent: 'center'
},
col2: {
paddingTop: 50,
paddingLeft: 30,
justifyContent: 'center'
}
});
The result would be that when Red or Black buttons are pushed, the key should be added to the array so it would be displayed in the lower part of the code but I can't find the way of doing it. Here is the full code. Also, any other advice about what I'm doing wrong is welcomed. I've just started learning React. Thank you all!
You should read basic documentation of react-native the key prop in TouchableOpacity is work as id not for key value like array. Try following code
class Foo extends React.Component {
constructor(props) {
super(props);
this.state = {
red: 0,
black: 0,
};
}
onClick = (name) => {
let selected = this.state[name];
selected++;
this.setState({ [name]: selected });
};
renderButton = (name) => {
return (
<TouchableOpacity onPress={this.onClick.bind(this, name)}>
<Text>{name}</Text>
</TouchableOpacity>
);
};
render() {
const { red, black } = this.state;
return (
<View>
{this.renderButton('red')}
{this.renderButton('black')}
{red.map(() => (
<Text>red</Text>
))}
{black.map(() => (
<Text>black</Text>
))}
</View>
);
}
}
Maybe you could try to pass the desired value to the function called onPress to add it to the desired array.
handlePressBlack(passedValue) {
this.setState(prevState => ({ countBlack: prevState.countBlack + 1 });
this.setState(RedBlackArray: this.RedBlackArray.concat(passedValue));
}
<TouchableOpacity key='black' onPress={() => this.handlePressBlack('Black')}>
<Text style={styles.button.buton2}>black!</Text>
</TouchableOpacity>

How to update data in first component when added data in another component

I have two components with realm database one is for listing and other is for adding data. But my problem is that i can't update list when data is adding into second component. I have tried App state listener also but it's not triggering when user come at first screen.
This is list component
import React, { Component } from "react";
import AppScreen from "../AppScreen.js";
import realm from "../databases/RealmController.js";
import colors from "../Ui/colors.js";
import Swipeout from "react-native-swipeout";
import { Icon } from "react-native-vector-icons";
import { NavigationActions } from "react-navigation";
import Dash from "react-native-dash";
import AppStateListener from "react-native-appstate-listener";
import {
AppState,
AppRegistry,
StyleSheet,
Text,
Image,
Button,
View,
FlatList,
TouchableHighlight,
TouchableOpacity,
Alert,
StatusBar,
TextInput
} from "react-native";
type Props = {};
export default class ReminderList extends Component<Props> {
state = {
data: [],
loading: true,
refresh: false,
appState: AppState.currentState
};
static navigationOptions = {
header: null,
title: " List"
};
handleActive() {
console.warn("The application is now active!");
}
handleBackground() {
console.warn("The application is now in the background!");
}
handleInactive() {
console.warn("The application is now inactive!");
}
componentDidMount() {
//this.fetchData();
AppState.addEventListener("change", this.handleAppStateChange);
}
componentWillUnmount() {
AppState.removeEventListener("change", this.handleAppStateChange);
}
gotoAddReminder = () => {
// handle navigation
this.props.screenProps.rootNavigation.navigate("addReminder");
};
handleAppStateChange = nextAppState => {
if (nextAppState === "active") {
this.setState({ data: null });
this.fetchData();
this.setState({ refresh: true });
// console.warn("hello i active");
//this.flatList.scrollToIndex({ animated: true, index: 0 });
}
else {
this.setState({ refresh: false });
// console.warn("hello i inactive");
}
this.setState({ appState: nextAppState });
};
fetchData() {
let reminderList = realm.objects("Reminder");
this.setState({ data: reminderList });
}
renderClientRow(item) {
return (
<TouchableHighlight underlayColor="rgba(192,192,192,1,0.6)">
<View style={styles.cardView}>
<View style={styles.dateView}>
<Text style={styles.dateText}>18</Text>
<Text style={styles.monthText}>Jan</Text>
</View>
<View
style={{
width: 1,
backgroundColor: colors.darkGray,
marginLeft: 15,
marginRight: 20
}}
/>
<View style={{ flexDirection: "row", marginTop: 15, width: "100%" }}>
<View style={{ flexDirection: "column" }}>
<Text style={styles.titleText}>{item.name}</Text>
<Text style={(styles.item, { marginTop: 5 })}>location</Text>
<Dash
style={{
width: 300,
marginTop: 10,
height: 1,
marginRight: 15
}}
/>
<View
style={{
flex: 1,
flexDirection: "row",
marginTop: 5,
marginBottom: 15
}}
>
<Image
style={{
width: 15,
height: 15,
marginTop: 5,
marginRight: 10
}}
source={require("../Image/ic_date.png")}
/>
<Text style={styles.item}>0.40 pm</Text>
</View>
</View>
</View>
</View>
</TouchableHighlight>
);
}
render() {
return (
<View style={styles.container}>
<AppStateListener
onActive={this.handleActive}
onBackground={this.handleBackground}
onInactive={this.handleInactive}
/>
<FlatList
ref={(c) => { this.flatList = c }}
data={this.state.data}
extraData={this.state.refresh}
renderItem={({ item }) => this.renderClientRow(item)}
keyExtractor={item => item.id}
/>
<TouchableOpacity
activeOpacity={0.5}
onPress={() => {
this.gotoAddReminder();
}}
style={styles.TouchableOpacityStyle}
>
<Image
source={{
uri:
"https://reactnativecode.com/wp-content/uploads/2017/11/Floating_Button.png"
}}
style={styles.FloatingButtonStyle}
/>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 0
},
MainContainer: {
justifyContent: "center",
flex: 1,
margin: 10
},
TouchableOpacityStyle: {
position: "absolute",
width: 50,
height: 50,
alignItems: "center",
justifyContent: "center",
right: 30,
bottom: 30
},
FloatingButtonStyle: {
resizeMode: "contain",
width: 50,
height: 50
},
cardView: {
backgroundColor: "#fff",
borderWidth: 0.5,
paddingLeft: 15,
paddingRight: 10,
marginLeft: 10,
marginTop: 10,
marginRight: 10,
borderRadius: 5,
flexDirection: "row"
},
item: {
fontSize: 16,
color: colors.darkGray
},
itemRight: {
fontSize: 18,
textAlign: "right"
},
titleText: {
fontSize: 20,
color: "black",
fontWeight: "400"
},
dateText: {
fontSize: 32,
color: colors.appColor,
fontWeight: "500"
},
monthText: {
fontSize: 22,
color: colors.appColor,
fontWeight: "500"
},
dateView: {
alignItems: "center",
justifyContent: "center",
flexDirection: "column",
marginLeft: 15,
marginRight: 15,
marginTop: 15,
marginBottom: 15
},
rightText: {
fontSize: 22,
color: "black",
textAlign: "right",
fontWeight: "bold"
},
myStarStyle: {
color: "yellow",
backgroundColor: "transparent",
textShadowColor: "black",
textShadowOffset: { width: 1, height: 1 },
textShadowRadius: 2
},
myEmptyStarStyle: {
color: "white"
}
});
This is AddData component
import React, { Component } from "react";
import realm from "../databases/RealmController.js";
import styles from "../Ui/AddClientStyles.js";
import { TextInputLayout } from "rn-textinputlayout";
import DatePicker from "react-native-datepicker";
import {
AppRegistry,
StyleSheet,
Text,
TouchableHighlight,
Button,
View,
ScrollView,
Image,
Alert,
StatusBar,
TextInput
} from "react-native";
const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
type Props = {};
export default class AddReminder extends Component<Props> {
state = {
to: "",
from: "",
name: "",
note: "",
location: ""
};
handlePress = async () => {
var Id = realm.objects("Reminder").length + 1;
realm.write(() => {
realm.create("Reminder", {
id: Id,
name: this.state.name,
note: this.state.note,
location: this.state.location,
to: this.state.to,
from: this.state.from
});
});
this.props.navigation.goBack();
};
render() {
return (
<ScrollView style={styles.container}>
<View style={styles.container}>
<View style={styles.profileContainer} />
<View style={styles.bottomContainer}>
<Text style={[styles.titleText, styles.titleStyle]}>
Basic Information
</Text>
<TextInputLayout style={{ marginTop: 0 }}>
<TextInput
style={styles.textInput}
placeholder={"Reminder Title"}
onChangeText={text => this.setState({ name: text })}
/>
</TextInputLayout>
<TextInputLayout style={styles.inputLayout}>
<TextInput
style={styles.textInput}
placeholder={"Note"}
onChangeText={text => this.setState({ note: text })}
/>
</TextInputLayout>
<TextInputLayout style={styles.inputLayout}>
<TextInput
style={styles.textInput}
placeholder={"Location"}
onChangeText={text => this.setState({ location: text })}
/>
</TextInputLayout>
<Text style={[styles.titleText, styles.titleStyle]}>
Date & Time
</Text>
<View style={styles.dateToContainer}>
<View style={{ flexDirection: "column", width: "30%" }}>
<Text style={styles.textInput}>From</Text>
</View>
<View styles={{ flexDirection: "column", width: "70%" }}>
<DatePicker
style={{ width: 200 }}
date={this.state.from}
mode="datetime"
format="YYYY-MM-DD HH:mm"
confirmBtnText="Confirm"
cancelBtnText="Cancel"
customStyles={{
dateIcon: {
position: "absolute",
left: 0,
top: 4,
marginLeft: 0
},
dateInput: {
marginLeft: 36
}
}}
minuteInterval={10}
onDateChange={datetime => {
this.setState({ from: datetime });
}}
/>
</View>
</View>
<View style={styles.dateContainer}>
<View style={{ flexDirection: "column", width: "30%" }}>
<Text style={styles.textInput}>To</Text>
</View>
<View styles={{ flexDirection: "column", width: "70%" }}>
<DatePicker
style={{ width: 200 }}
date={this.state.to}
mode="datetime"
format="YYYY-MM-DD HH:mm"
confirmBtnText="Confirm"
cancelBtnText="Cancel"
customStyles={{
dateIcon: {
position: "absolute",
left: 0,
top: 4,
marginLeft: 0
},
dateInput: {
marginLeft: 36
}
}}
minuteInterval={10}
onDateChange={datetime => {
this.setState({ to: datetime });
}}
/>
</View>
</View>
<TouchableHighlight
style={styles.btnStyle}
onPress={() => {
this.handlePress();
}}
underlayColor="#fff"
>
<Text style={styles.btnText}>Add Reminder</Text>
</TouchableHighlight>
<TouchableHighlight
style={{marginTop:20}}>
<Text/>
</TouchableHighlight>
</View>
</View>
</ScrollView>
);
}
}
When u use this.props.navigation.goBack(); those components not render again or not call any method that component so can use this.props.navigation.navigate('your_route_path');

conditionality render headerRight - React Native

I have to render headerRight conditionally in navigation options.
Right now
static navigationOptions = ({ navigation }) => ({
title: i18N.t('atmbranchpickHeader'),
headerRight: (
<TouchableHighlight
underlayColor="#E22F39"
onPress={() => {
navigation.navigate("home");
}}
>
<Image
style={{ marginRight: 20 }}
source={require('../../resources/toolbar/home_white.png')}
/>
</TouchableHighlight>
),
headerTintColor: "white",
headerStyle: {
backgroundColor: "#E22F39"
// top: 30
}
});
My Component
import React, { Component } from "react";
import {
View,
TextInput,
Text,
TouchableOpacity,
TouchableHighlight,
StyleSheet,
AsyncStorage,
BackHandler,
Image,
FlatList,
Dimensions,
TouchableWithoutFeedback
} from "react-native";
import i18n from "../../i18n/i18n.js";
import { colors } from "../../constants/colors.js";
import Storage from "../../utils/AsyncStorage.js";
class AtmBranchTypeSelect extends Component {
// Render callBack
constructor(props) {
super(props);
this.state = {
data: [
],
stBool: false,
}
}
async componentWillMount() {
BackHandler.addEventListener('hardwareBackPress', () => this.props.navigation.goBack());
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', () => this.props.navigation.goBack());
}
static navigationOptions = ({ navigation }) => ({
title: i18n.t('atmbranchpickHeader'),
headerRight: (
<TouchableHighlight onPress={() => {
navigation.navigate('home');
}}>
<Image style={{ marginRight: 20 }} source={require('../../resources/toolbar/home_white.png')} />
</TouchableHighlight>),
headerTintColor: 'white',
headerStyle: {
backgroundColor: colors.themeColor,
// top: 30
}
});
_renderList = ({ item }) => {
return (
<TouchableWithoutFeedback onPress={(event) => this._selectedItem(item.key)}>
<View style={styles.listRowContainer}>
<View style={styles.listinside1Container}>
<Image style={styles.listImage} source={item.icon} />
<View style={styles.listContainer} onPress={(event) => this._selectedItem(item.text)} >
<Text style={styles.listHeader} >{item.header}</Text>
<Text style={styles.listValue} >{item.value}</Text>
</View>
</View>
<Image style={styles.listimgArrow} source={require('../../resources/toolbar/chevron_right_grey.png')} />
</View>
</TouchableWithoutFeedback>
);
}
// Render callBack
render() {
return (
<View style={styles.mainWrapper} >
<FlatList data={this.state.data} renderItem={this._renderList} />
</View>
);
}
}
const styles = StyleSheet.create({
mainWrapper: {
flex: 1,
height: Dimensions.get('window').height,
width: Dimensions.get('window').width,
flexDirection: 'column',
justifyContent: 'flex-start'
},
listRowContainer: {
flexDirection: 'row',
marginTop: 10,
height: 80,
backgroundColor: '#FFFFFF',
justifyContent: 'space-between',
borderBottomWidth: 1,
borderColor: 'lightgray'
},
listinside1Container: {
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center'
},
listContainer: {
alignItems: 'flex-start',
justifyContent: 'center',
flexDirection: 'column',
backgroundColor: '#FFFFFF',
// borderBottomWidth: 1,
// borderColor: 'lightgray'
},
listHeader: {
color: 'black',
fontFamily: 'Roboto-Medium',
marginLeft: 10,
fontSize: 18,
},
listValue: {
fontFamily: 'Roboto-Regular',
marginTop: 4,
color: 'black',
marginLeft: 10,
fontSize: 14,
},
listImage: {
alignSelf: 'center',
height: 25,
width: 25,
margin: 10
},
listimgArrow: {
// flex: 1,
// flexDirection:'row',
alignSelf: 'center',
height: 25,
width: 25,
margin: 10
},
listVal: {
borderWidth: 1,
borderRadius: 10,
color: 'darkgreen',
borderColor: 'white',
backgroundColor: 'white',
fontWeight: 'bold'
},
});
export default AtmBranchTypeSelect;
From the code I have, headerRight will be displayed in all scenarios. consider I have a scenario like based on state value I have to enable/disable headerRight Button .
for example this.state.stBool? headerRight:(.....) : null
I have to render in this way.Please guide me to achieve this.
You could nest the navigation options inside the render and toggle it based on the state value. Haven't tested and not positively on performace. Hope it helps.
import React, { Component } from "react";
import {
View,
TextInput,
Text,
TouchableOpacity,
TouchableHighlight,
StyleSheet,
AsyncStorage,
BackHandler,
Image,
FlatList,
Dimensions,
TouchableWithoutFeedback
} from "react-native";
import i18n from "../../i18n/i18n.js";
import { colors } from "../../constants/colors.js";
import Storage from "../../utils/AsyncStorage.js";
class AtmBranchTypeSelect extends Component {
// Render callBack
constructor(props) {
super(props);
this.state = {
data: [],
stBool: false
};
}
async componentWillMount() {
BackHandler.addEventListener("hardwareBackPress", () =>
this.props.navigation.goBack()
);
}
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", () =>
this.props.navigation.goBack()
);
}
_renderList = ({ item }) => {
return (
<TouchableWithoutFeedback onPress={event => this._selectedItem(item.key)}>
<View style={styles.listRowContainer}>
<View style={styles.listinside1Container}>
<Image style={styles.listImage} source={item.icon} />
<View
style={styles.listContainer}
onPress={event => this._selectedItem(item.text)}
>
<Text style={styles.listHeader}>{item.header}</Text>
<Text style={styles.listValue}>{item.value}</Text>
</View>
</View>
<Image
style={styles.listimgArrow}
source={require("../../resources/toolbar/chevron_right_grey.png")}
/>
</View>
</TouchableWithoutFeedback>
);
};
// Render callBack
render() {
const { stBool } = this.state;
const navigationOptions = ({ navigation }) => ({
title: i18n.t("atmbranchpickHeader"),
headerRight: stBool ? (
<TouchableHighlight
onPress={() => {
navigation.navigate("home");
}}
>
<Image
style={{ marginRight: 20 }}
source={require("../../resources/toolbar/home_white.png")}
/>
</TouchableHighlight>
) : null,
headerTintColor: "white",
headerStyle: {
backgroundColor: colors.themeColor
// top: 30
}
});
return (
<View style={styles.mainWrapper}>
<FlatList data={this.state.data} renderItem={this._renderList} />
</View>
);
}
}

Resources