React Native: doesn't get the latest data from an array - javascript

I have a chat app, this is just like a chatbot. So I am not using any database, all the messages are temporary. So I decided to use JavaScript arrays, whenever the user types anything in the TextInput and presses the button, it pushes that message to the array. And in another place, I am mapping everything from the array and displaying them in the screen using <Text> component. Now, the Text component isn't showing any data which is pushed to the array, it only shows the dummy messages I entered to check them. Check out the code below:
import { React, useState } from 'react';
import { Alert, ScrollView, SafeAreaView, Text, StyleSheet, TextInput, Button, TouchableHighlight, Image } from 'react-native';
function ChatWindow(props) {
const [userMessage, setUserMessage] = useState("");
const [isTextInputFocused, setFocused] = useState(false);
const styles = StyleSheet.create({
mainSafeAreaView: {
flex: 1,
backgroundColor: 'white',
},
bottomSafeAreaView: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
top: '93%',
left: '2%',
bottom: '2%',
marginBottom: '10%',
flexDirection: 'row',
justifyContent: 'space-between'
},
userMessageTextInput: {
height: 40,
width: 300,
borderColor: isTextInputFocused == true ? "blue" : "gray",
alignItems: 'center',
borderWidth: 1,
borderRadius: 20,
paddingLeft: 10,
paddingRight: 10
},
sendButton: {
marginLeft: 5,
height: 40,
width: 40
},
usersMessage: {
backgroundColor: "#3386ff",
borderRadius: 20,
padding: 7,
margin: 3,
color: "white",
textAlign: "center"
},
userMessageAreaView: {
flexDirection: "row",
justifyContent: "flex-end",
marginRight: 10
},
botMessage: {
backgroundColor: "#e7e0e0",
borderRadius: 20,
padding: 7,
margin: 3,
color: "black",
textAlign: "center"
},
botMessageAreaView: {
flexDirection: "row",
justifyContent: "flex-start",
marginLeft: 10
},
scrollArea: {
marginTop: 40
}
})
var userMessagesSent = [
{sentBy: "user", content: "Bursa will be the capital of ottoman"},
{sentBy: "araf", content: "Agree"}
];
function sendMessage(messageSent) {
userMessagesSent.push({sentBy: "user", content: messageSent});
setUserMessage("");
console.log(userMessagesSent)
}
return (
<SafeAreaView style={styles.mainSafeAreaView}>
<ScrollView style={styles.scrollArea}>
{
userMessagesSent.map((item, index) =>
<SafeAreaView key={index} style={item.sentBy == "user" ? styles.userMessageAreaView : styles.botMessageAreaView}>
<Text key={index} style={item.sentBy == "user" ? styles.usersMessage : styles.botMessage}>{item.content}</Text>
</SafeAreaView>
)
}
</ScrollView>
<SafeAreaView style={styles.bottomSafeAreaView}>
<TextInput
value={userMessage}
style={styles.userMessageTextInput}
placeholder="Enter a message"
onChangeText={(text) => setUserMessage(text)}
onFocus={() => setFocused(true)}
onSubmitEditing={() => setFocused(false)}
onEndEditing={() => setFocused(false)}
/>
<TouchableHighlight
onPress={() => sendMessage(userMessage)}
underlayColor={'white'}
>
<Image
source={require(".././assets/send.png")}
style={styles.sendButton}
resizeMode='cover'
/>
</TouchableHighlight>
</SafeAreaView>
</SafeAreaView>
);
}
export default ChatWindow;
I really have to complete the app fast, so if you could help me then it would be great.

you're using a variable to store state. If you want the data to persist then you need to use useState(). Otherwise when the data changes your component wont re-render. Thats why you arent seeing the update. For more information on using variables vs state see this stack overflow question
const [userMessageSent, setUserMessageSent] = useState([
{sentBy: "user", content: "Bursa will be the capital of ottoman"},
{sentBy: "araf", content: "Agree"}
])
function sendMessage(messageSent) {
setUserMessagesSent(prevState => ([...prevState, {sentBy: "user", content: messageSent}])
setUserMessage("");
}

I think it has something to do with the way you save massages. Is there a specific reason why you are not saving your array with the messages in the state? Maybe that would fix your problem

Related

React Native TouchableOpacity not working with position absolute

I have a list that shows results matching the user's input. The onPress of the touchableOpacity is not working in this list. This list is positioned absolutely and positioned below its parent view (positioned relative). The only time I can get the onPress to work is when I remove the top:48 style from list and the onPress works for the single element which is directly onTop of the parent.
export default function IndoorForm(props) {
return (
<View style={styles.container}>
<View style={styles.parent}>
<Autocomplete
style={styles.autocomplete}
autoCompleteValues={autoCompleteValues}
selectedLocation={props.getDestination}
></Autocomplete>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignSelf: "center",
position: "absolute",
top: Platform.OS === "android" ? 25 + 48 : 0 + 48,
width: Dimensions.get("window").width - 30,
zIndex: 500
},
parent: {
position: "relative",
flex: 1,
borderWidth: 2,
borderColor: "#AA2B45",
height: 48,
backgroundColor: "#fff",
flexDirection: "row",
alignItems: "center",
paddingLeft: 16,
paddingRight: 16,
justifyContent: "space-between"
}
}
export default function AutoComplete(props: AutoCompleteProps) {
const { autoCompleteValues } = props;
return (
<View style={styles.container}>
<FlatList
data={autoCompleteValues}
renderItem={({ item }: { item: POI }) => (
<TouchableOpacity onPress={() => console.log("Haal")} key={item.displayName} style={styles.list}>
<Text style={styles.text}>{item.displayName}</Text>
<Entypo name={"chevron-thin-right"} size={24} color={"#454F63"} />
</TouchableOpacity>
)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
position: "absolute",
flex: 1,
width: Dimensions.get("window").width - 30,
top: 48,
borderWidth: 2,
borderColor: "#F7F7FA",
backgroundColor: "#F7F7FA",
zIndex: 999
},
list: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
paddingTop: 15,
paddingLeft: 10,
paddingBottom: 10,
borderBottomColor: "rgba(120, 132, 158, 0.08)",
borderBottomWidth: 1.4,
zIndex: 999
}
}
I know you solved your issue already, but you can use this magical library react-native-gesture-handler, import your Touchables from there and they don't care about being inside the parent views. You can touch them regardless.
Resolved this by dynamically adjusting the container height so that the touchableOpacity is within the container. The issue was I positioned the list outside of the parent (as intended by styling) but for onPress to work it has to be inside the parent.
let autocompleteHeight = autoCompleteValues.length * 65
<View style={[styles.container, {height: autocompleteHeight}]}>

Make Search using firebase in react native

I am new to react native and firebase. I want to make a search bar that can search all data from firebase according to Barcode value, but I'm facing some errors while doing it. I think that my code is wrong somewhere but don't know where. I have transferred the firebase credentials to dbConfig.js . Here is my firebase data firebase data and my code:
import React,{Component} from 'react';
import { View, Text,TextInput,StyleSheet,Image, Button} from 'react-native';
import firebase from './dbConfig';
export default class ListItem extends Component {
render() {
return (
<>
<View style={styles.BackGround}>
<View style={styles.SectionStyle}>
<Image
source={require('./mic.png')} //mic image here
style={styles.ImageStyle}
/>
<TextInput
style={{ flex: 1, justifyContent: 'center', textAlign: 'center', fontSize: 12}}
placeholder="Search for Product"
underlineColorAndroid="transparent"
//onChangeText={(text) => this.setState({data: text})}
onSubmitEditing = {(text)=> this.setState({data: text})}
value = {this.state.data}
// onSubmitEditing={()=>this._search}
//onSubmitEditing={()=>this.componentWillMount}
/>
<Image
source={require('./usr.png')} //icon image here
style={styles.ImageStyle2}
/>
</View>
<View>
<Text>{this.state.items}</Text>
</View>
</View>
</>
);
}
constructor(props){
super(props);
this.state= {
items: '',
data: '',
};
}
componentWillMount(){
var ref = firebase.database().ref('/');
ref.child(this.state.data).on("value", snapshot =>{
console.log(snapshot.val().info.Price);
//if(snapshot.val().Price == this.state.data){
//this.setState({items: Object.values(snapshot.val())});
//}
//else{
//alert('there is problem');
//}
});
}
}
const styles = StyleSheet.create({
BackGround: {
backgroundColor: '#22abb6',
height: '100%'
},
SectionStyle: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
// borderWidth: 0.8,
// borderColor: '#000',
shadowColor:'#176f75',
marginTop: 50,
height: 40,
borderRadius: 10,
margin: 10,
},
ImageStyle: {
padding: 10,
marginLeft: 10,
margin: 5,
height: 25,
width: 25,
resizeMode: 'stretch',
alignItems: 'center',
},
ImageStyle2: {
padding: 10,
marginLeft: 10,
marginRight: 10,
margin: 5,
height: 25,
width: 25,
resizeMode: 'stretch',
alignItems: 'center',
},
});
I did it by changing the follows:
//adding this in TextInput
onSubmitEditing = {this.componentWillMount}
//on changing the function compoundWillMount to async()
componentWillMount= async()=>{

React Native app works on iOS but comes up with error on Android posts.map not defined

I have created a simple program to display information from my website on the app. It works on iOS but on my Android device an error shows up :
posts.map is not a function. This is my code:
import React, { Component } from 'react';
import {
View,
Text,
ActivityIndicator,
ScrollView,
StyleSheet,
Image,
Header,
} from 'react-native';
let lw = 100;
import Img from 'react-image';
let li = 'https://www.teanewsnetwork.com/profileicons/';
let bean = 'azure.jpg';
export default class App extends Component {
state = {
loading: true,
error: false,
posts: [],
};
componentWillMount = async () => {
try {
const response = await fetch(
'https://www.teanewsnetwork.com/api/fetcharticles.php?code=#NIL7*GKD60JTRTEFZ0CkvpHMJJW^-9q&starting=0&limit=40'
);
const posts = await response.json();
this.setState({ loading: false, posts });
} catch (e) {
this.setState({ loading: false, error: true });
}
};
renderPost = ({ id, title, content, authorimage, authorname }, i) => {
let b = { authorname };
return (
<View style={styles.postContent}>
<View
style={{
flex: 1,
flexDirection: 'column',
textAlign: 'center',
justifyContent: 'center',
alignItems: 'center',
}}>
<Text style={styles.postauthor}>{title} </Text>
<Image
source={{
uri: `https://teanewsnetwork.com/profileicons/${authorimage}`,
}}
defaultSource={require('./contact-outline.png')}
style={{
width: lw,
height: lw,
flex: 1,
justifyContent: 'center',
alignItems: 'center',
borderRadius: lw / 2,
}}
/>
<Text style={styles.postauthor}>{authorname}</Text>
</View>
<Text style={styles.postBody}>{content}</Text>
</View>
);
};
render() {
const {posts, loading, error} = this.state
if (loading) {
return (
<View style={styles.center}>
<ActivityIndicator animating={true} />
</View>
)
}
if (error) {
return (
<View style={styles.center}>
<Text>
Failed to load posts!
</Text>
</View>
)
}
return (
<ScrollView style={styles.container}>
{posts.map(this.renderPost)}
</ScrollView>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
borderBottomWidth: 0,
borderBottomColor: 'red',
top: 100,
zIndex: 6,
},
postauthor: {
flex: 1,
borderBottomWidth: 0,
borderBottomColor: 'red',
paddingVertical: 25,
fontSize: 18,
paddingRight: 15,
left: 10,
justifyContent: 'center',
alignItems: 'center',
textAlign: 'center',
},
postContent: {
flex: 1,
borderBottomWidth: 20,
borderBottomColor: '#EEE',
borderRadius: 4,
fontSize: 18,
left: 0,
paddingRight: 15,
justifyContent: 'center',
alignItems: 'center',
textAlignVertical: 'center',
textAlign: 'center',
},
postBody: {
marginTop: 1,
fontSize: 18,
color: 'black',
left: 10,
textAlign: 'center',
},
center: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
I am a beginner coder on react native and would like to have some help here. The code works on iOS emulator with EXPO but doesnt work on my Android Device.
Thanks in Advance!
Most likely posts is not a array, check the type of posts.

Place Element over TextBox

I am trying to place an Avatar element over my TextInput so that it will look like a conventional search bar, but it doesn't go over the TextInput Please isn't it working, or can another better method of putting the search icon over the TextInput be suggested, Thank you
import { Avatar } from 'react-native-elements';
import FontAwesome
from './node_modules/#expo/vector-icons/fonts/FontAwesome.ttf';
import MaterialIcons
from './node_modules/#expo/vector-icons/fonts/MaterialIcons.ttf';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {timePassed: false};
}
state = {
fontLoaded: false
};
async componentWillMount() {
try {
await Font.loadAsync({
FontAwesome,
MaterialIcons
});
this.setState({ fontLoaded: true });
} catch (error) {
console.log('error loading icon fonts', error);
}
}
render() {
setTimeout(() => {
this.setState({timePassed: true})
}, 4000);
if (!this.state.timePassed) {
return <Splash/>;
} else {
return (
<View style={BackStyles.container}>
<Avatar style={BackStyles.searchIcon} icon={{ name: 'search', size: 25, }}/>
<TextInput placeholder="Search for your herbs.."
underlineColorAndroid={'transparent'} style={BackStyles.textBox}
/></View>
);
}
}
}
const BackStyles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'flex-start',
alignSelf: 'stretch',
flex: 1,
backgroundColor: '#E2E2E2',
marginTop: 20,
// width: '100%'
},
textBox: {
flex: 1,
height: 45,
padding: 4,
// textAlignVertical: 'top',
paddingLeft: 20,
// marginRight: 5,
flexGrow: 1,
// fontSize: 18,
color: '#000',
backgroundColor: '#fff',
// textAlign: 'center'
},
searchIcon:{
position: 'absolute',
alignSelf: 'stretch',
height: 45,
flex: 1,
top: 50,
flexGrow: 1,
padding: 4
}
});
You can use Flexbox's justifyContent feature to force the TextInput to the left and the search icon to the right. If you put a border on the container and not the TextInput, the entire thing will appear as there is a search icon fixed onto the right of the TextInput, when, in reality, they are two separate components.
// styles
const styles = StyleSheet.create({
searchBox: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
borderWidth: 1,
borderColor: 'black',
},
});
// the component
<View style={styles.searchBox}>
<TextInput ...yourprops />
<Avatar ...yourprops />
</View>
If you want to read more about justifyContent and how godly Flexbox is, you should check out Chris Coyier's Flexbox guide.

Take picture, save and access Camera with react-native

I am studing react-native a 4 months and I am Build my App. I got problems with Camera. I am trying to take a picture, save and access the photo. I take a picture but I don't know where picture goes and how to acess.
I am using expo import camera, because when I use from react a get some error.
this is my code:
import React, {Component} from 'react';
import {Text, View, TouchableOpacity, Image,TouchableHighlight,Vibration} from 'react-native';
//import Camera from 'react-native-camera';
import {Camera, Permissions,} from 'expo';
const myStyle = {
container: {
flex: 1,
flexDirection: 'row',
},
preview: {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center'
},
capture: {
flex: 0,
backgroundColor: '#fff',
borderRadius: 5,
color: 'red',
padding: 10,
margin: 40
},
main2: {
flex: 1,
//alignItems: 'flex-start',
flexDirection: 'row',
justifyContent: 'space-between',
},
main: {
flex: 1,
},
borda: {
//flex: 0.1,
alignItems: 'flex-end',
backgroundColor: 'black',
height: 110,
},
borda2: {
backgroundColor: 'black',
width: 60,
},
borda3: {
width: 60,
backgroundColor: 'black',
},
borda4: {
height: 120,
backgroundColor: 'black',
//flex: 1,
alignItems: 'center',
flexDirection: 'row',
justifyContent:'space-between',
},
texto:{
fontSize: 18,
marginBottom: 40,
color: 'white',
},
textoButton:{
fontSize: 18,
color: 'white',
marginTop: 5,
},
button:{
alignSelf: 'flex-end',
alignItems: 'center',
backgroundColor:'transparent',
flexDirection: 'row',
justifyContent:'space-between'
},
cameraStyle:{
width: 70,
height: 57,
//margin:30,
alignItems: 'center',
tintColor: 'white',
},
flipStyle:{
width: 52,
height: 57,
marginLeft:10,
alignItems: 'center',
tintColor: 'white',
},
gallerystyle:{
width: 64,
height: 57,
marginLeft:10,
alignItems: 'center',
tintColor: 'white',
marginRight: 10,
},
closeStyle:{
width: 56,
height: 57,
marginTop: 30,
marginRight: 20,
alignItems: 'flex-end',
tintColor: 'white',
justifyContent:'flex-end'
},
box:{
width: 'auto',
justifyContent: 'space-between',
flexDirection: 'column',
alignItems: 'center',
},
};
export default class CameraAcess extends Component {
constructor(props) {
super(props);
this.state = {hasCameraPermission: null, type: Camera.Constants.Type.back,};
}
async componentWillMount() {
const {status} = await Permissions.askAsync(Permissions.CAMERA);
this.setState({hasCameraPermission: status === 'granted'});
}
snap = async function(){
if (this.camera) {
this.camera.takePictureAsync().then(data => {
FileSystem.moveAsync({
from: data,
to: '${FileSystem.documentDirectory}photos/Photo_${this.state .photoId}.jpg',
}).then(() => {
this.setState({
photoId: this.state.photoId + 1,
});
Vibration.vibrate();
})
.catch((e) => {
console.log(e, 'ERROR');
});
})
.catch((e) => {
console.log(e, 'takePicture ERROR');
});
}
console.log('I took the picture');
};
cameraPhoto = require('./Images/camera.png');
flipPhoto = require('./Images/flip.png');
closePhoto = require('./Images/close.png');
galleryPhoto = require('./Images/gallery.png');
render() {
const { main,main2, borda, borda2, borda3,borda4,cameraStyle,flipStyle,closeStyle,box,textoButton,gallerystyle} = myStyle;
const {hasCameraPermission} = this.state;
if (hasCameraPermission === null) {
return <View/>;
} else if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
} else {
return (
<View style={main}>
<Camera style={main} type={this.state.type}>
<TouchableHighlight onPress={() => {this.props.navigator.push({id: 'MenuPrincipal'});}}
style={borda} underlayColor={'black'} activeOpacity={0.6}>
<Image source={this.closePhoto} style={[closeStyle]}/>
</TouchableHighlight>
<View style={main2}>
<View style={[borda2]}/>
<View style={[borda3]}/>
</View>
<View style={[borda4]}>
<TouchableOpacity onPress={() => {this.setState({type: this.state.type === Camera.Constants.Type.back
? Camera.Constants.Type.front : Camera.Constants.Type.back,});}}>
<View style={box}>
<Image source={this.flipPhoto} style={[flipStyle]}/>
<Text style={textoButton}>
Flip
</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={() => {this.snap()}}>
<View style={box}>
<Image source={this.cameraPhoto} style={[cameraStyle]}/>
<Text style={textoButton}>
Capture
</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={() => {false}}>
<View style={box}>
<Image source={this.galleryPhoto} style={[gallerystyle]}/>
<Text style={textoButton}>
Gallery
</Text>
</View>
</TouchableOpacity>
</View>
</Camera>
</View>
);
}
}
}
Someone help me to solve this problem and please be especific and clearly in your explanation, every details are necessary to me. I need this to end my App.
If I were you I would do
console.log(data);
then you can see what the promise returns in the XDE. You should, at the very least, see the following properties: height, width, uri. Uri will show you exactly where that image is being stored in the cache.

Categories