Fetching data from AWS SQS and wait to render ReactJs - amazon-web-services

So we are having an issues where we send a request to SQS and then on the receive message it returns no data.
To try and fix this we threw in a while loop to poll for an extended period of time; however that really doesn't work because we cannot sleep between polls and it seems as if they are all happening asynchronously.
I say that because if the value does get returned (happens about 50% of the time) it will re render the next screen as many time as cap is left and polling never gets set to false. Could someone please help us out!
render() {
return (
<Navigator
renderScene={this.renderScene.bind(this)}
navigator={this.props.navigator}
navigationBar={
<Navigator.NavigationBar style={{backgroundColor: 'transparent'}}
routeMapper={NavigationBarRouteMapper} />
} />
);
}
renderScene() {
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" hidden={true}/>
<View style={styles.topContainer}>
<View style={styles.bannerContainer}>
<View style={{flexDirection: 'column', flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Image style={styles.mark} source={require('./yb.png')} />
</View>
</View>
<View style={styles.credentialContainer}>
<View style={styles.inputContainer}>
<Icon style={styles.inputPassword} name="person" size={28} color="#FFCD00" />
<View style={{flexDirection: 'row', flex: 1, marginLeft: 2, marginRight: 2, borderBottomColor: '#e0e0e0', borderBottomWidth: 2}}>
<TextInput
style={styles.input}
placeholder="Username"
autoCorrect={false}
placeholderTextColor="#e0e0e0"
onChangeText={(text) => this.setState({username: text})}
value={this.state.username}>
</TextInput>
</View>
</View>
<View style={styles.inputContainer}>
<Icon style={styles.inputPassword} name="lock" size={28} color="#FFCD00" />
<View style={{flexDirection: 'row', flex: 1, marginLeft: 2, marginRight: 2, borderBottomColor: '#e0e0e0', borderBottomWidth: 2}}>
<TextInput
style={styles.input}
placeholder="Password"
autoCorrect={false}
secureTextEntry={true}
placeholderTextColor="#e0e0e0"
onChangeText={(text) => this.setState({password: text})}
value={this.state.password}>
</TextInput>
</View>
</View>
<TouchableOpacity style={styles.forgotContainer}>
<Text style={{color: '#e0e0e0'}}>Forgot Password</Text>
</TouchableOpacity>
</View>
</View>
<TouchableHighlight
underlayColor="#D6AB00"
onPress={this.login}
style={styles.signInButtonContainer}>
<Text style={styles.signInText}>Sign In</Text>
</TouchableHighlight>
</View>
);
}
login() {
var polling = true;
if(this.state.username.length == 0){
Alert.alert("Error","No email entered");
}
else if(this.state.password.length == 0){
Alert.alert("Error","No password entered");
}
else
{
info.username = this.state.username;
info.password = this.state.password;
AWS.sendMessage('****',JSON.stringify(info), (error,result) =>{
if(error != null) console.log("Error Occured Attempting to Send A Message")
else {
var cap=0;
while(cap <= 30 && polling){
cap = cap+1;
AWS.receiveMessages('****'+info.username, (error, result) =>{
if(error != null) console.log("Error");
else{
if(result){
try{
polling = false;
if(result[0] == "[]")
{
console.log(result[0]);
console.log(typeof result[0]);
Alert.alert("Error","Username/Password Incorrect");
}
else
{
console.log(result[0]);
console.log(typeof result[0]);
var temp = JSON.parse(result[0]);
this.props.navigator.replace({
id: 'MapIOS',
data: {
username: info.username,
ofAge: temp[0].ofAge,
uid: temp[0].u_ID
},
});
}
}
catch(e){
console.log(e);
}
}
AWS.deleteMessage('***'+info.username, result[1], (error) => {
if(error != null) console.log("Error");
});
}
});
}
return
}
});
}
}
};

The problem is that you are calling AWS.ReceiveMessage in a loop.
When you call AWS.ReceiveMessage, the call is asynchronous. Meaning, it will return immediately. It does not wait for your callback to be called. So your loop can be exhausted before any of the callbacks get called.
Trying to set your polling variable from your callback function is not a safe way to "protect" your callback.
You need to restructure your function so that the second AWS.ReceiveMessage does not happen until after your callback has been called from the first AWS.ReceiveMessage.
Generally speaking, don't loop.

Some important facts about SQS that you need to keep in mind when using it:
SQS is not "first in, first out". Messages may not be received in the same order as they were put into the queue. So if you add messages "1" then "2", you may receive them as "2" then "1".
Even if messages are in the queue, you may not get a message when you call ReceiveMessage.
You may receive the same message more than once. For example, if you added message "1" to the queue, you may get back "1" then "1" again later. So you need to ensure that message processing is idempotent and repeat-safe.
All of the above is due to the fact that SQS is distributed and redundant. It guarantees that you will get your messages, but it does not guarantee the order, or the number of times that messages will be received.
Update:
This was my original answer, but I don't think it's the primary issue with the code. I'm leaving it here since I think it's still valuable information.

Related

my Accordion list expanded all items at same time (react native elements)

I use react-native-elements library.
in ListItem Accordion there is onPress option to expand and unexpand list items.
but when I press one item, all of items expand!
screen shot 1
here is part of my code:
export class MyList extends Component {
state= {
expanded:false,
};
constructor(props) {
super(props);
this.state = {
expanded:false
};
}
handleToggle=()=>{
const {expanded}=this.state;
if(expanded){
this.setState({expanded:false});
}else{
this.setState({expanded:true})
}
}
render() {
return (
...
<View>
{list.map((l, i) => (
<ListItem.Accordion key={i}
content={
<>
<ListItem.Content>
<ListItem.Title>{l.name}</ListItem.Title>
<Avatar title={l.name[0]} source={{ uri: l.avatar_url }} />
</ListItem.Content>
</>
}
isExpanded={this.state.expanded}
onPress={this.handleToggle}
>
<ListItem key={i} bottomDivider>
<ListItem.Content>
<ListItem.Subtitle>{l.city}</ListItem.Subtitle>
<View style={styles.subtitleView}>
<Image source={require('../Images/4.5_stars.svg.png')} style={styles.ratingImage}/>
<Text style={styles.ratingText}>5 votes</Text>
</View>
</ListItem.Content>
<ListItem.Chevron />
</ListItem>
</ListItem.Accordion>
))}
...
is it my props problem?? if yes, how can I pass the item for each "onPress"??
Surely you already solved your problem.
I had the same problem and I solved it myself since I couldn't find a solution.
It turns out that it was very simple and probably arises from not being used to the React way of working.
A component must be created for your custom <ListItem.Accordion>,
then you get something like
{Turneras ? (Turneras.map((Turnera, i) => (
<ItemAccordion Turnera={Turnera} ></ItemAccordion>
))) : null
}
As easy as that, since each component will have its state expanded and it works perfectly.

In Android Modal - wrapping content in GestureHandlerRootView not fixing react-native-gesture-handler

I am using expo ^40.0.0.
I am trying to get react-native-gesture-handler components to work in a <Modal> from react-native in Android. I followed docs here - https://docs.swmansion.com/react-native-gesture-handler/docs/#for-library-authors
It stays to wrap in <GestureHandlerRootView>, I did this but it doesn't fix the issue.
I created a snack demo of issue - https://snack.expo.io/#noitidart/frisky-carrot
Here you see a "Tapped here count: 0". Please try tapping it, you will see it doesn't increment the counter.
You will see a "RN BUTTON" this works but it is not from react-native-gesture-handler.
Here is my code from the snack:
import * as React from 'react';
import { Text, View, Modal, Button as RNButton } from 'react-native';
import {
BaseButton,
GestureHandlerRootView
} from 'react-native-gesture-handler';
export default function App() {
return (
<Modal animationType="slide" transparent={false}>
<Example />
</Modal>
);
}
const Example = function () {
const [cnt, setCnt] = React.useState(0);
return (
<View style={{ justifyContent: 'center', flex: 1 }}>
<RNButton title="rn button" onPress={() => alert('hi')} />
<GestureHandlerRootView>
<BaseButton
onPress={() => {
// alert('pressed');
setCnt(cnt + 1);
}}
>
<View style={{ backgroundColor: 'steelblue', height: 100 }}>
<Text>Tapped here count: {cnt}</Text>
</View>
</BaseButton>
</GestureHandlerRootView>
</View>
);
};

Auth.changePassword throws 'incorrect username or password'

I am using react native and AWS for my backend. I am trying to add a feature that allows users to be able to change their password after they have logged into the app. I believe I should be able to do this using the Auth.changePassword function (AWS doc). For some reason, I am getting an error that the username or password is incorrect.
When testing, the user returns a CognitoUser, the oldPassword is definitely correct, and the newPassword throws errors if it does not meet the character settings. I am lost as to what the issue could be. Should I also be using completeChangePassword in conjunction?
import React from 'react';
import {Auth} from '#aws-amplify/auth';
export default class ChangePassword extends React.Component {
constructor(props) {
super(props);
this.state = {
oldPassword: '',
newPassword: '',
};
}
handleChangePassword = async () => {
const { oldPassword, newPassword } = this.state;
await Auth.currentAuthenticatedUser()
.then(user => {
return Auth.changePassword(user, oldPassword, newPassword)
})
.then(data => console.log(data))
.then(user => this.props.navigation.navigate('Home'))
.catch(err => console.log(err))
}
render() {
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.text_header}>Change Password</Text>
</View>
<Animatable.View
animation='bounceInUp'
style={styles.footer}
>
<View style={styles.footer}>
<Text style={styles.text_footer}>Old Password</Text>
<View style={styles.action}>
<Feather
name='lock'
color='#05375a'
size={20}
/>
<TextInput
placeholder='Enter old password'
style={styles.textInput}
autoCapitalize='none'
onChangeText={(val) => this.setState({ oldPassword: val })}
/>
</View>
<Text style={styles.text_footer}>New Password</Text>
<View style={styles.action}>
<Feather
name='lock'
color='#05375a'
size={20}
/>
<TextInput
placeholder='Enter new password'
style={styles.textInput}
autoCapitalize='none'
onChangeText={(val) => this.setState({ newPassword: val })}
/>
</View>
<View style={styles.button}>
<TouchableOpacity
style={styles.signIn}
onPress={this.handleChangePassword}
>
<LinearGradient
colors={['#55B142', '#155843']}
style={styles.signIn}
>
<Text style={[ styles.textSign, { color: '#fff' }]}>Submit</Text>
</LinearGradient>
</TouchableOpacity>
</View>
<View style={{ alignItems: 'center'}}>
<View style={{flexDirection: 'row', alignItems: 'center', paddingTop: 5 }}>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('EditProfile')}
style={[styles.signUp, {
//borderColor: '#155843',
//borderWidth: 1,
marginTop: 15,
}]}
>
<Text style={[styles.textSign, {
color: '#155843'
}]}>Go Back</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Animatable.View>
</View>
);
}}
Turns out the problem was that the account that was logged in wasn't verified which is why it would reject the email address.

How to add Click Event on FlatList Item in React Native?

I am working in demo Application for learning React native And I need to render clickable FlatList item.
Here is Render and itemClick function:
render() {
return (
<View style={styles.container}>
<View>
<FlatListData list={this.state.itemList} />
</View>
</View>
);
}
itemClick(item){
console.log('click on item', item);
}
I have already declare FlatListData functional component for that :
const FlatListData = ({list}) => {
return (
<FlatList
data={list}
keyExtractor={(item, index) => index.toString()}
renderItem={itemList}
/>
);
};
In FlatList component, RenderItem attribute have again custom component for single item i.e :
const itemList = ({item, index}) => {
return (
<TouchableOpacity onPress={this.itemClick(item)} style={styles.catalogContainer}>
<Image
source={{uri: item.img}}
style={styles.imageStyle}
/>
</TouchableOpacity>
);
};
But this code is not working. It will give me error like : Undefined is not an object (eveluting _this.itemClick)
Here in which way and where Should I write click function for item ?
Any one have a answer that can solve my problem ?
NOTE :
All code is written in one js file. My Render function is inside my class component. and other two declarative component are out of that class component.
I need that item inside that click function. But I don't know how to pass parameter inside function.
There are a couple of things you can do to fix your problem.
You need to move your itemClick function inside itemList as an arrow function.
const itemList = ({ item, index }) => {
itemClick = item => {
console.log("click on item", item);
};
return (
<TouchableOpacity
// onPress={this.itemClick(item)}
onPress={() => this.itemClick(item)}
style={styles.catalogContainer}
>
<Image source={{ uri: item.img }} style={styles.imageStyle} />
</TouchableOpacity>
);
};
Pass your itemClick function as props to child component
render() {
return (
<View style={styles.container}>
<FlatListData list={this.state.itemList} onItemClick={this.itemClick} />
</View>
);
}
itemClick = (item) => {
console.log('click on item', item);
}
Now you can call onItemClick prop inside itemList
const FlatListData = ({ list, onItemClick }) => {
itemList = ({ item }) => (
<TouchableOpacity
onPress={() => onItemClick(item)}
style={styles.catalogContainer}
>
<Image source={{ uri: item.img }} style={styles.imageStyle} />
</TouchableOpacity>
);
return (
<FlatList
data={list}
keyExtractor={(item, index) => index.toString()}
renderItem={this.itemList}
/>
);
};
Hope this helps you. Feel free for doubts.

render a scrollview after a condition in react native

i need to display a scrollview in react native application, after a condition using if. In fact, i have a list of items in firebase that contain text and title but sometimes they may contain images also. I need to display that list of text and titles in the exact same order and also the images if there is any. here the code i used
_renderScrollViewContent() {
const data = this.state.items
if (data.image) {
return (
<View>
{data.map((item, i) =>
<View key={i}>
<Image source={require('path')}/>
<Text>{item.image}</Text>
<Text>{item.title}</Text>
<Text>{item.text} </Text>
</View>
)}
</View>
);
}
else
{
return (
<View>
{data.map((item, i) =>
<View key={i} style={styles.row}>
<Text>{item.image}</Text>
<Text>{item.title}</Text>
<Text>{item.text} </Text>
</View>
)}
</View>
);
}
}
render() {
const headerHeight = this.state.scrollY.interpolate({
inputRange: [0, HEADER_SCROLL_DISTANCE],
outputRange: [HEADER_MAX_HEIGHT, HEADER_MIN_HEIGHT],
extrapolate: 'clamp',
});
const imageOpacity = this.state.scrollY.interpolate({
inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE],
outputRange: [1, 1, 0],
extrapolate: 'clamp',
});
const imageTranslate = this.state.scrollY.interpolate({
inputRange: [0, HEADER_SCROLL_DISTANCE],
outputRange: [0, -50],
extrapolate: 'clamp',
});
return (
<View style={styles.fill}>
<ScrollView
style={styles.fill}
scrollEventThrottle={16}
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {y: this.state.scrollY}}}]
)}
>
{this._renderScrollViewContent()}
</ScrollView>
);
}
I Now it seems that it's not even checking for the condition (data.image) and it seems that it always goes directly to the else condition and displays only the text.
PS: i'm using this tutorial to make a scrollable header and it's working perfectly fine in displaying text but not images inside them https://medium.com/appandflow/react-native-scrollview-animated-header-10a18cb9469e.
Also, if delete the if condition, i always get the blank spaces between items .. any suggestion
so that's the code that finally worked for me ..i hope it will help someone else in the future
_renderScrollViewContent() {
var productList = [];
this.state.items.forEach(function (item) {
if (!item.image) {
productList.push(
<View key={item.key}>
<Text>{item.title}</Text>
<Text>{item.text}</Text>
<Text>{item.image}</Text>
</View>
);
}
else {
productList.push(
<View key={item.key}>
<Text>{item.title}</Text>
<Text>{item.text}</Text>
<Text>{item.image}</Text>
<Image source={require('path')}>
<View>
<Text>{item.legend}</Text>
</View>
</Image>
</View>
);
}
}.bind(this));
return (
<View>
{productList }
</View>
);
}