I'm trying to execute a function and navigate to the next screen using React-navigation and creating an Axios post
I've already tried combining both function's but It doesn't seem to execute the createOrder function
If I run the createOrder function alone it does work
onPress={
() => {
this.createOrder
this.props.navigation.navigate('Cart', {
order : this.state.order
});
}
}
import React from 'react';
import {
View,
StyleSheet,
Text,
Image,
TouchableOpacity
} from 'react-native';
//Redux
import { connect } from 'react-redux';
import { addItemToCart, removeItem } from '../../actions/ProductActionCreators';
//Products
import Products from '../../components/products/Products';
// Api Url
import ApiUrl from '../../helpers/ApiUrl'
//UI LIBRARY
import { Input, Button } from 'react-native-elements';
import {LinearGradient} from "../../components/LinearGradient";
import { ButtonGroup } from 'react-native-elements';
import Icon from "react-native-vector-icons/Ionicons";
//AXIOS
import axios from 'axios';
export class ProductsListView extends React.Component {
constructor(props) {
super(props);
const { rows } = this.props.navigation.state.params;
const arrays = Object.values( {rows});
this.state = {
arrays,
filteredProducts: arrays,
selectedIndex: 2
};
this.updateIndex = this.updateIndex.bind(this)
}
createOrder () {
axios.post( ApiUrl + 'api/order/post', {
code: "4f",
status: "waiting",
user_name: "salman",
user_id: 1,
club_id: 1,
})
.then(response => {
this.setState({
order: response.data,
});
console.log('created order',this.state.order)
})
.catch(function (error) {
console.log('error',error);
})
}
updateIndex (selectedIndex) {
this.setState({selectedIndex})
}
filterAll(){
}
filterStrong(){
this.setState({
arrays: this.state.arrays[0].products.filter(item => item.type == "strong" )
})
console.log(this.state.arrays)
}
filterNormal(){
}
render() {
const component1 = () => <Icon
name="ios-star"
size={15}
color="gold"
/>
const component2 = () => <Icon
name="ios-beer"
size={15}
color="gold"
onPress={() => this.filterStrong}
/>
const component3 = () => <Icon
name="ios-wine"
size={15}
color="gold"
/>
const buttons = [{ element: component1 }, { element: component2 }, { element: component3 }]
const { selectedIndex } = this.state
return (
<View style={styles.container} >
<Image
style={styles.imageCard}
source={
{
uri:
this.state.arrays[0].image
}
}
/>
<Text style={styles.title} >
{this.state.arrays[0].name}
</Text>
<Products
products={this.state.arrays[0].products}
addItemToCart={this.props.addItemToCart}
removeItem={this.props.removeItem}
/>
<View style={{
justifyContent:'center',
width: '100%',
padding: 50,
paddingTop:20,
}}>
<Button
title="Go to my cart"
containerStyle={{ flex: -1 }}
buttonStyle={styles.signUpButton}
linearGradientProps={{
colors: ['#dd016b', '#dd016b'],
start: [1, 0],
end: [0.2, 0],
}}
ViewComponent={LinearGradient}
titleStyle={styles.signUpButtonText}
// onPress={this.createOrder}
onPress={
() => {
this.createOrder
this.props.navigation.navigate('Cart', {order : this.state.order});
}
}
/>
</View>
</View>
)
}
}
const mapDispatchToProps = {
addItemToCart,
removeItem
}
export default connect(null, mapDispatchToProps) (ProductsListView);
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
width:'100%',
backgroundColor: 'black',
},
signUpButtonText: {
// fontFamily: 'bold',
fontSize: 13,
},
signUpButton: {
width: 250,
borderRadius: 50,
height: 45,
},
title: {
color:'white',
fontSize:32,
height: 100,
position: 'relative',
backgroundColor: '#00000054',
width: "100%",
textAlign: 'center',
paddingTop: 30,
},
imageCard:{
height:100,
width:'100%',
position: "absolute",
top: 0,
backgroundColor: 'white'
},
button: {
padding: 5,
borderRadius: 25,
margin: 5,
backgroundColor: '#DD016B',
color: 'white',
alignItems: 'center',
justifyContent: 'center',
},
})
I'm trying to navigate to the next screen with the data from I get from my Axios post.
You are not calling the createOrder function.
Try this:
<Button
title="Go to my cart"
containerStyle={{ flex: -1 }}
buttonStyle={styles.signUpButton}
linearGradientProps={{
colors: ["#dd016b", "#dd016b"],
start: [1, 0],
end: [0.2, 0]
}}
ViewComponent={LinearGradient}
titleStyle={styles.signUpButtonText}
// onPress={this.createOrder}
onPress={this.onGoToMyCartPressed}
/>;
And onGoToMyCartPressed would look like:
onGoToMyCartPressed = () => {
this.createOrder(); // <- Call the function
this.props.navigation.navigate("Cart", { order: this.state.order });
};
And, if you want to navigate after the order has been created, then, have your createOrder return the promise, and you can chain off of it in the onGoToMyCartPressed
Like so:
createOrder() {
// Return the promise from here
return axios.post( ApiUrl + 'api/order/post', {
code: "4f",
status: "waiting",
user_name: "salman",
user_id: 1,
club_id: 1,
}).then(response => {
this.setState({
order: response.data,
});
console.log('created order',this.state.order)
}).catch(function (error) {
console.log('error',error);
})
}
And modify the onGoToMyCartPressed to use the promise returned.
onGoToMyCartPressed = () => {
// CHange the page once the order has been craeted
this.createOrder().then(() => {
this.props.navigation.navigate("Cart", { order: this.state.order });
})
};
Related
Good day.
I have managed to fetch an array of images from firestore database collection, the only problem is that it seems that I cannot loop over the array that I am retrieving from the database.
I need to dynamically display my images on the carousel.
import React, { useState, useEffect, useCallback } from 'react';
import { Text, Dimensions, StyleSheet, View, Image } from 'react-native';
import { SwiperFlatList } from 'react-native-swiper-flatlist';
import firestore from '#react-native-firebase/firestore';
import { white } from 'react-native-paper/lib/typescript/styles/colors';
import { color } from 'react-native-reanimated';
import Carousel from 'react-native-reanimated-carousel';
//const colors = ["tomato", "thistle", "skyblue", "teal"];
const names = [{"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/Ads%2FJB.png?alt=media&token=377f1629-6807-4343-b826-93d1c2bc5de6"}, {"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/Ads%2Fgymtarp.png?alt=media&token=b2d1c923-2b5c-4066-bf8f-dc12de399059"}, {"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/photos%2Fb75d0848-b37f-4584-ab46-f355ca838e83.jpg?alt=media&token=adaa8559-de91-4ced-b056-84300123102e"}, {"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/Ads%2FSANDO.png?alt=media&token=274c946b-7f20-4c07-8545-431a0558257c"}];
const App = () => {
const [ads, setAds] = useState([]); // Initial empty array of ads
useEffect(() => {
const subscriber = firestore()
.collection('AdsDB')
//.orderBy('Menu', 'asc')
.onSnapshot(querySnapshot => {
//const ads = [];
/*
querySnapshot.forEach(documentSnapshot => {
ads.push({
...documentSnapshot.data(),
key: documentSnapshot.id,
});
});
*/
querySnapshot.forEach(doc => {
const { AdImage } = doc.data();
ads.push({
//id: doc.id,
AdImage,
//Price,
});
});
setAds(ads);
console.log(ads);
//console.log(Object.entries(ads));
});
// Unsubscribe from events when no longer in use
return () => subscriber();
}, []);
return (
<View style={styles.container}>
<SwiperFlatList
autoplay
autoplayDelay={2}
autoplayLoop
index={2}
showPagination
data={ads}
renderItem={({ item }) => (
<View style={[styles.child, { backgroundColor: item }]}>
<Text style={styles.text}>{item.AdImage}</Text>
<Image
style={{
width: "100%",
height: "30%",
position: 'absolute',
top:0,
alignItems: 'center',
justifyContent: 'center'}}
source={{uri : item.AdImage}}
resizeMode={'stretch'} // cover or contain its upto you view look
/>
</View>
)}
/>
</View>
)
};
const { width } = Dimensions.get('window');
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: 'white', },
child: { width, justifyContent: 'center', height: '100%' },
text: { fontSize: width * 0.1, textAlign: 'center' },
});
export default App;
Thank you for answering my question. Mabuhay! I'm from the Philippines.
The problem I am seeing is that probably meanwhile you are receiving asynchronously the snapshots, the setState did not ended running (a race condition between the velocity receiving snapshots and the exact time needed to persist the state)
I would try to delay the state change and use the previous state value in the setter, like this:
useEffect(() => {.
const subscriber = firestore()
.collection('AdsDB')
.onSnapshot(querySnapshot => {
querySnapshot.forEach(doc => {
const { AdImage } = doc.data();
setTimeout(() => {
setAds((prevAds) => [...prevAds, AdImage]);
}, 500);
});
console.log(ads);
//console.log(Object.entries(adsFromFirebase));
});
These are my code, Sir. It gives an empty array.
import React, { useState, useEffect, useCallback } from 'react';
import { Text, Dimensions, StyleSheet, View, Image } from 'react-native';
import { SwiperFlatList } from 'react-native-swiper-flatlist';
import firestore from '#react-native-firebase/firestore';
import { white } from 'react-native-paper/lib/typescript/styles/colors';
import { color } from 'react-native-reanimated';
const colors = ["tomato", "thistle", "skyblue", "teal"];
const names = [{"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/Ads%2FJB.png?alt=media&token=377f1629-6807-4343-b826-93d1c2bc5de6"}, {"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/Ads%2Fgymtarp.png?alt=media&token=b2d1c923-2b5c-4066-bf8f-dc12de399059"}, {"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/photos%2Fb75d0848-b37f-4584-ab46-f355ca838e83.jpg?alt=media&token=adaa8559-de91-4ced-b056-84300123102e"}, {"AdImage": "https://firebasestorage.googleapis.com/v0/b/pindot-65e7c.appspot.com/o/Ads%2FSANDO.png?alt=media&token=274c946b-7f20-4c07-8545-431a0558257c"}];
const App = () => {
const [ads, setAds] = useState([]); // Initial empty array of ads
useEffect(() => {
const subscriber = firestore()
.collection('AdsDB')
.onSnapshot(querySnapshot => {
querySnapshot.forEach(doc => {
const { AdImage } = doc.data();
setTimeout(() => {
setAds((prevAds) => [...prevAds, AdImage]);
}, 500);
});
console.log(ads);
//console.log(Object.entries(adsFromFirebase));
});
// Unsubscribe from events when no longer in use
return () => subscriber();
}, []);
/*
useEffect(() => {
const subscriber = firestore()
.collection('AdsDB')
//.orderBy('Menu', 'asc')
.onSnapshot(querySnapshot => {
//const ads = [];
/*
querySnapshot.forEach(documentSnapshot => {
ads.push({
...documentSnapshot.data(),
key: documentSnapshot.id,
});
});
querySnapshot.forEach(doc => {
const { AdImage } = doc.data();
ads.push({
//id: doc.id,
AdImage,
//Price,
});
});
setAds(ads);
//console.log(ads);
//console.log(Object.entries(ads));
});
// Unsubscribe from events when no longer in use
return () => subscriber();
}, []);
*/
return (
<View style={styles.container}>
<SwiperFlatList
autoplay
autoplayDelay={2}
autoplayLoop
index={2}
data={ads}
renderItem={({ item }) => (
<View style={[styles.child, { backgroundColor: item.colors }]}>
<Text style={styles.text}>{item.AdImage}</Text>
<Image
style={{
width: "100%",
height: "30%",
position: 'absolute',
top:0,
alignItems: 'center',
justifyContent: 'center'}}
source={{uri : item.AdImage}}
resizeMode={'stretch'} // cover or contain its upto you view look
/>
{/*}*/}
</View>
)}
/>
</View>
)
};
const { width } = Dimensions.get('window');
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: 'white', },
child: { width, justifyContent: 'center', height: '100%' },
text: { fontSize: width * 0.1, textAlign: 'center' },
});
export default App;
This is the output.
LOG Running "myApp" with {"rootTag":21}
LOG []
I wanted to how to solve this error... this is not my code I am fixing bugs in someone else's code. "I wanted to how to dispatch to store with use effect Hook".
as I researched it says it says I can dispatch to store inside a function without a use effect Hook I wanted to know how to modify it in this code,
also if someone know how to getrid of "MapStateToProps" with the useSelect hook that will also be more helpfull for me inorder to improve this code...
LoginScreen.js
import React, { Component } from 'react';
import {
View, Text,
Image,
Dimensions,
ImageBackground,
SafeAreaView,
Alert,
Modal, Button,
StatusBar,
TextInput,
TextInputComponent,
Linking,
StyleSheet
} from 'react-native';
// import { PropTypes } from 'prop-types';
// import NetInfo from "#react-native-community/netinfo";
import { widthPercentageToDP as wp, heightPercentageToDP as hp } from 'react-native-responsive-screen';
// import * as Animatable from 'react-native-animatable';
import AsyncStorage from '#react-native-community/async-storage'
import { showMessage, hideMessage } from "react-native-flash-message";
const { width, height } = Dimensions.get('window');
import styles from './styles';
import Buttons from '../../../uiElements/Buttons/RoundButtons'
import VerificationCodeText from '../../../uiElements/VerificationCodeText'
import { connect } from 'react-redux';
import startUpActions from '../../../redux/StartUp/actions';
import Loading from '../../../uiElements/Loading';
import { ScrollView, TouchableHighlight, TouchableOpacity } from 'react-native-gesture-handler';
import { textFocusColor, textDefaultColor } from '../../../contents'
import TextInputField from '../../../uiElements/TextInput';
const { loginApp, getCustomerDetailsByEmail, clearProps, getAgentExposableId } = startUpActions;
const imageWidth = Dimensions.get('window').width;
// const imageWidth = Dimensions.get('window').width;
class StartScreen extends Component {
constructor(props) {
super(props);
this.state = {
hasFocusPhoneNo: false,
iseyeactivenew: true,
iseyeactivecurrent: true,
userId: '',
password: '',
hasFocusUsername: false,
hasFocusPassword: false,
}
}
static getStateFromProps(props, state) {
if (props.jwttoken != undefined) {
if (props.jwttoken == 'errlogin') {
}
}
}
static getDerivedStateFromProps(props, state) {
if (props.jwttoken != undefined) {
if (props.jwttoken == 'errlogin') {
showMessage({
textStyle: { paddingLeft: 10 },
titleStyle: { paddingLeft: 10 },
message: "Error",
description: "Username or Password incorrect",
type: "default",
backgroundColor: "red", // background color
color: "#ffffff",
duration: 3850
});
_storeAccess = async () => {
props.dispatch(clearProps())
}
_storeAccess()
} else {
_storeAccess = async () => {
await AsyncStorage.setItem('access_token', props.jwttoken);
const appIdRequest = await AsyncStorage.getItem('appIdrequest')
props.dispatch(getCustomerDetailsByEmail(props.jwttoken, '', state.userId))
//props.dispatch(clearProps())
}
_storeAccess();
}
}
if (props.customerDetailsAllResult != undefined) {
// console.log(props.customerDetailsAllResult.responseDto.customerDetailsId)
if (props.customerDetailsAllResult.responseDto == null) {
props.dispatch(clearProps())
} else {
_storeAccess = async () => {
await AsyncStorage.setItem('customerWalletId', props.customerDetailsAllResult.responseDto.agentSenderDetailsId.toString());
await AsyncStorage.setItem('email', props.customerDetailsAllResult.responseDto.email.toString()) //not change
await AsyncStorage.setItem('useremail', props.customerDetailsAllResult.responseDto.email.toString()) //when change coporate mail this will change
await AsyncStorage.setItem('agentSenderDetails', JSON.stringify(props.customerDetailsAllResult.responseDto))
const access_token = await AsyncStorage.getItem('access_token')
Console.log("navigate", access_token)
if (access_token != null) {
props.navigation.navigate('TabView')
}
// props.navigation.navigate('MoneyTransfer2')
props.dispatch(clearProps())
}
_storeAccess();
}
}
if (props.agentExposableId != undefined) {
if (props.agentExposableId == null) {
props.dispatch(clearProps()) //loginurl https://qabankingauth.monexfintech.com/v1/auth/authenticate
} else {
_storeAccess = async () => { await AsyncStorage.setItem('agentExposableId', props.agentExposableId); }
// props.navigation.navigate('MoneyTransfer2')
props.dispatch(clearProps())
}
_storeAccess();
}
return null;
}
componentDidMount() {
// console.log('lll')
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.customerDetailsAllResult !== this.props.customerDetailsAllResult) {
}
if (prevProps.jwttoken !== this.props.jwttoken) {
console.log(this.props.jwttoken)
}
}
getData = async () => {
try {
const accesstoken = await AsyncStorage.getItem('access_token')
if (accesstoken !== null) {
this.props.dispatch(userShow(accesstoken))
this.setState({ islogin: true })
console.log('jjj')
// this.props.navigation.navigate('TabView')
} else {
this.props.dispatch(getBranchesList())
this.setState({ islogin: false })
// this.props.navigation.navigate('TabView')
}
} catch (e) {
console.log(e)
}
}
onChangeText = (key, val) => {
this.setState({ [key]: val }, () => {
})
}
onpressphoneno = () => {
this.setState({ hasFocusPhoneNo: true })
this.setState({ postcodeerror: false })
}
btnPress = async () => {
this.props.navigation.navigate('LoginScr')
if (this.state.userId == '' || this.state.password == '') {
showMessage({
textStyle: { paddingLeft: 10 },
titleStyle: { paddingLeft: 10 },
message: "Error",
description: "Please enter Username and Password",
type: "default",
backgroundColor: "red", // background color
color: "#ffffff",
duration: 3850
});
} else {
try {
const obj = {
username: this.state.userId,
password: this.state.password,
grantType: 'Agent Customer',
agentRegNumber: 'MXAG01'
}
await AsyncStorage.setItem('email', this.state.userId);
await AsyncStorage.setItem('useremail', this.state.userId);
await AsyncStorage.setItem('password', this.state.password);
await AsyncStorage.setItem('access_token', ' eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJjaGF0aHVyYW5nYUBjb2RlbGFudGljLmNvbSIsInVzZXJfaWQiOjMsImV4cCI6MTYxNTQzODI4NywiaXNfdGZhX2VuYWJsZWQiOm51bGwsImlhdCI6MTYxNTQzNDY4NywidGZhRGVmYXVsdFR5cGUiOm51bGwsImNsaWVudF9jb2RlIjoiTU4ifQ.lncV1VQ-T0dNPsME0_FvRF-2TQShHiwP66aFoT0fhV58QaR-Sn0ZVEBPSiGxxQ9NWnzbaCpev61Hkex6EPBxNA');
// this.props.dispatch(getFirstValue());
this.props.dispatch(getAgentExposableId());
this.props.dispatch(loginApp(obj))
this.props.dispatch(clearProps());
} catch (error) {
console.log(error);
}
//this.props.navigation.navigate('LoginScr')
}
}
clickPrivacypolicy() {
Linking.canOpenURL("https://spoton.money/policy-procedures-refund-terms-gdpr").then(supported => {
if (supported) {
Linking.openURL("https://spoton.money/policy-procedures-refund-terms-gdpr");
} else {
console.log("Don't know how to open URI: " + this.props.url);
}
});
}
render() {
// const { navigate } = this.props.navigation;
return (
<SafeAreaView style={style.container}>
<ScrollView style={{ backgroundColor: '#343A4F', }}>
<View style={{ backgroundColor: '#343A4F', height: '100%' }}>
<ImageBackground source={require('../../../images/ellipse.png')} style={{ width: '100%', height: '60%' }}>
<View style={{ alignItems: 'center', paddingTop: wp('15%') }}>
<Image
style={{ width: wp('45%'), height: wp('15%') }}
source={require('../../../images/spotonmoneylogo.png')}
/>
</View>
{this.props.loading && <Loading navigation={this.props.navigation} animating={true} />}
<View style={{ paddingLeft: wp('5%'), paddingRight: wp('5%'), backgroundColor: '#343A4F', marginTop: wp('50%') }}>
{/* <TextInput
placeholder="Username"
placeholderTextColor={textDefaultColor}
onFocus={() =>this.setState({ hasFocusUsername: true })}
onBlur={() => this.setState({ hasFocusUsername: false })}
onChangeText={(val) => this.setState({ userId: val })}
style={
this.state.hasFocusUsername ?
styles.focusedTextInput :
styles.txtstyle
}
/> */}
<TextInputField
placeholdertext="Username"
valuetext={this.state.email}
onFocusFunc={() => this.setState({ hasFocusUserName: true })}
onBlurFunc={() => this.setState({ hasFocusUserName: false })}
onChangeTextFunc={value => this.onChangeText('userId', value)}
iserrortext={this.state.errorlastnamestate}
editabletext={false}
keyboardType1='email'
// texterror={this.state.errorlastnametextstate}
// hasFocustext={this.state.hasFocusUserName}
/>
<TextInputField
placeholdertext="Password"
valuetext={this.state.password}
onFocusFunc={() => this.setState({ hasFocusPassword: true })}
onBlurFunc={() => this.setState({ hasFocusPassword: false })}
onChangeTextFunc={value => this.onChangeText('password', value)}
iserrortext={this.state.errorlastnamestate}
editabletext={false}
secureTextEntrytxt={true}
// texterror={this.state.errorlastnametextstate}
hasFocustext={this.state.hasFocusPassword}
/>
{/* <TextInput
placeholder="Password"
placeholderTextColor={textDefaultColor}
secureTextEntry={true}
onFocus={() => this.setState({ hasFocusPassword: true })}
onBlur={() => this.setState({ hasFocusPassword: false })}
onChangeText={(val) => this.setState({ password: val })}
style={
this.state.hasFocusPassword ?
styles.focusedTextInput :
styles.txtstyle
}
/> */}
</View>
<View style={{ paddingTop: wp('10%'), alignItems: 'center' }}>
<TouchableOpacity onPress={() => this.props.navigation.navigate('Verification')}>
<Text style={{ color: 'white' }}>Forgot Password</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.btnPress()}>
<Buttons text="Log In" btnfontSize={wp('4%')}
btnbackgroundColor='#F15622'
btntxtncolor="#ffffff"
btnMarginRight={imageWidth / 1000}
btnMarginLeft={imageWidth / 1000}
onPress={() => this.btnPress()} />
</TouchableOpacity>
<View style={{ paddingTop: wp('4%') }}>
<Text style={{ color: 'white', fontSize: wp('4%') }}>Don't have an account?
<TouchableOpacity onPress={() => this.props.navigation.navigate('VerificationSignUp')}>
<Text style={{ color: '#2793E1', fontWeight: 'bold', textDecorationLine: 'underline' }}>
Sign Up
</Text>
</TouchableOpacity>
</Text>
</View>
<View style={{ padding: wp('4%'), marginTop: hp('4%'), alignContent: 'center' }}>
<TouchableOpacity >
<Text style={{ color: 'white', fontSize: wp('3%') }}>By logging in you agree to the Spoton money
<TouchableOpacity onPress={() => this.clickPrivacypolicy()}>
<Text style={{ color: '#2793E1', fontSize: wp('3%'), paddingTop: wp('1%') }}>
Privacy policy .
</Text>
</TouchableOpacity>
and acknowledge our
<TouchableOpacity onPress={() => this.clickPrivacypolicy()}>
<Text style={{ color: '#2793E1', fontSize: wp('3%'), paddingTop: wp('1%') }}>
Terms & Conditions.
</Text>
</TouchableOpacity>
</Text>
</TouchableOpacity>
</View>
</View>
</ImageBackground>
</View>
</ScrollView>
</SafeAreaView>
);
}
}
const mapStateToProps = state => {
return {
...state.startUpReducer
}
// loading: state.startUpReducer.loading,
// jwttoken: state.startUpReducer.jwttoken,
// customerDetailsAllResult: state.startUpReducer.customerDetailsAllResult,
// agentExposableId: state.startUpReducer.exposable_id
};
export default connect(mapStateToProps)(StartScreen);
const style = StyleSheet.create({
container: {
backgroundColor: '#343A4F',
height: wp()
}
})
redux/Actions.js
loginApp: (value) => ({
type: actions.LOGIN_SCREEN,
value
}),
redux/reducer.js
case startUpActions.LOGIN_SCREEN:
return{
...state,
loading:true
}
case startUpActions.LOGIN_SCREEN_RESULT:
return{
loading:false,
jwttoken:action.result.jwttoken
}
case startUpActions.LOGIN_SCREEN_ERROR:
return{
loading:false,
jwttoken:'errlogin'
}
redux/saga.js
export function* loginApp(){
yield takeEvery(actions.LOGIN_SCREEN, function* (payload) {
const requestBody=payload.value
const url = loginURL;
console.log(requestBody);
console.log(url);
try {
const response = yield fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(requestBody)
});
console.log(response)
const result = yield response.json();
console.log(result)
if (response.ok) {
yield put({ type: actions.LOGIN_SCREEN_RESULT, result });
} else {
yield put({
type: actions.LOGIN_SCREEN_ERROR,
result
});
}
} catch (error) {
yield put({ type: actions.LOGIN_SCREEN_ERROR });
}
});
}
I'm programming this simple app in react native, but when I try to make the axios request I'm not able to concatenate the url and the "user" and "repo" const taken from the store.
console.log(apiurl) gives me "https://api.github.com/repos/undefined/undefined"
but if I type console.log(user) it gives me the actual value of user const.
How can I access create the axios request using user and repo const?
import {
View,
Text,
StyleSheet
} from 'react-native';
import { useSelector, useDispatch} from 'react-redux';
import { NavigationContainer, useNavigation } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import axios from 'axios';
import setResponse from '../actions';
import NetInfo from "#react-native-community/netinfo";
export default function homeScreen() {
const apiurl = 'https://api.github.com/repos/' + user + '/' + repo;
const user = useSelector(state => state.user);
const repo = useSelector(state => state.repo);
const response = useSelector(state => state.response)
const navigation = useNavigation();
const dispatch = useDispatch();
const [state, setState] = useState({
color: "",
isConnected: true,
});
const check = () => {
console.log(user);
console.log(repo);
console.log(apiurl);
axios.get('https://api.github.com/repos/'+ user+ '/' + repo).then(res => {
console.log(res.data.name);
dispatch(setResponse(res.data.message));
}).catch(error => console.log(error));
if (response === "Not Found") {
setState(prevState => {
return { ...prevState, color: "#ffacac" };
});
}
else if (state.isConnected == false) {
dispatch(setResponse("disconnected"));
setState(prevState => {
return { ...prevState, color: "#ffacac" };
});
}
else if (response == null) {
setState(prevState => {
return { ...prevState, color: "#caffda" };
});
}
}
return (
<View style={{flex: 1, backgroundColor: state.color}}>
<View style={styles.titleContainer}>
<Text style={styles.title}>Set the repository address</Text>
</View>
<View style={styles.githubLink}>
<Text style={styles.link1}>github.com</Text>
<View style={styles.inputContainer}>
<Text style={styles.link1}>/</Text>
<Text style={styles.link2} onPress={() => navigation.navigate('User')} >{user}</Text>
</View>
<View style={styles.inputContainer}>
<Text style={styles.link1}>/</Text>
<Text style={styles.link2} onPress={() => navigation.navigate('Repo')} >{repo}</Text>
</View>
</View>
<View style={styles.buttonContainer}>
<Text style={styles.button} onPress={check}>CHECK</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
titleContainer: {
flex: 1.5,
justifyContent: "center",
paddingLeft: 12,
},
title: {
fontSize: 28,
fontFamily: "OpenSans-SemiBold",
},
githubLink: {
flex: 3,
paddingLeft: 12,
justifyContent: "center",
},
inputContainer: {
flexDirection: "row",
},
link1: {
fontSize: 38,
fontFamily: "OpenSans-Regular",
},
link2: {
fontSize: 38,
fontFamily: "OpenSans-Regular",
color: "grey"
},
buttonContainer: {
flex: 5.5,
justifyContent: "flex-end",
alignItems: "flex-end",
padding: 8,
},
button: {
fontSize: 25,
fontFamily: "OpenSans-Bold",
}
});
First, you need to make sure that the selector data from the state is not empty. Before actually doing the request you can check if the values are empty/undefined.
I also would advise you to more structure the way you are doing requests now. The Redux Toolkit has some nice examples for structuring your code to make it more maintainable. See their site
Image of Error
I am using ios emulator and keep on receiving this error when i go to run the profile page. It first loads for a little bit then stops and the error pops up it says it's on the 'this.state.user.avatar' but i can't seem to see what i wrong with it? what am i doing wrong? if someone can help me that would be great!
This is my ProfileScreen.js file
import React from "react";
import {View, Text, StyleSheet, TouchableOpacity, Button, Image } from "react-native";
import Fire from '../utilities/Fire';
export default class ProfileScreen extends React.Component {
state = {
user: {}
};
unsubscribe = null;
componentDidMount() {
const user = this.props.uid || Fire.shared.uid
this.unsubscribe = Fire.shared.firestore
.collection("users")
.doc(user)
.onSnapshot(doc => {
this.setState({ user: doc.data() });
});
}
componentWillUnmount() {
this.unsubscribe();
};
render() {
return(
<View style={styles.container}>
<View style = {{ MarginTop: 64, alignItems: "Center" }}>
<View style={styles.avatarContainer}>
<Image style={styles.avatar} source={this.state.user.avatar ? { uri: this.state.user.avatar } : require("../assets/avatar.png")}
/>
</View>
<Text style={styles.name}>{this.state.user.name}</Text>
</View>
<View style={styles.subContainer}>
<View style={styles.stat}>
<Text style={styles.info}>8/10</Text>
<Text style={styles.Title}>Rewards</Text>
</View>
<View style={styles.stat}>
<Text style={styles.info}>80/100</Text>
<Text style={styles.Title}>Badges</Text>
</View>
</View>
<Button onPress={() => {Fire.shared.signOUt()}} title="Log Out" />
</View>
);
}
}
const styles = StyleSheet.create({
container:{
flex: 1,
},
avatarContainer:{
shadowColor: "#151734",
shadowRadius: 15,
shadowOpacity: 0.4
},
avatar: {
width: 136,
height: 136,
borderRadius: 68
},
name: {
marginTop: 24,
fontSize: 16,
fontWeight: "600"
},
subContainer: {
flexDirection: "row",
justifyContent: "space-between",
margin: 32,
},
stat: {
alignItems:"center",
},
info: {
color: "#4F566D",
fontSize: 18,
fontWeight: "300"
},
Title: {
color: "#C3C5CD",
fontSize: 12,
fontWeight: "500",
marginTop: 4
}
});
This is my Fire.js file
import FirebaseKeys from '../config';
import firebase from 'firebase';
require("firebase/firestore");
class Fire{
constructor() {
firebase.initializeApp(FirebaseKeys);
}
addPost = async({ text, localUri }) => {
const remoteUri = await this.uploadPhotoAsync(localUri, 'photos/${this.uid}/${Date.now()}');
return new Promise ((res, rej) => {
this.firestore
.collection("posts")
.add ({
text,
uid: this.uid,
timestamp: this.timestamp,
image: remoteUri
})
.then(ref => {
res(ref);
})
.catch(error => {
rej(error);
});
});
};
uploadPhotoAsync = async (uri, filename) => {
return new Promise(async (res, rej) => {
const response = await fetch(uri);
const file = await response.blob();
let upload = firebase
.storage()
.ref(filename)
.put(file);
upload.on(
"state_changed",
snapshot => {},
err => {
rej(err);
},
async () => {
const url = await upload.snapshot.ref.getDownloadURL();
res(url);
}
);
});
};
createUser = async user => {
let remoteUri = null
try {
await firebase.auth().createUserWithEmailAndPassword(user.email, user.password)
let db = this.firestore.collection("users").doc(this.uid)
db.set({
name: user.name,
email: user.email,
avatar: null
})
if (user.avatar) {
remoteUri = await this.uploadPhotoAsync(user.avatar, 'avatars/${this.uid}')
db.set({avatar: remoteUri }, { merge: true})
}
} catch (error) {
alert("Error: ", error);
}
};
signOut = () => {
firebase.auth().signOut();
};
get firestore(){
return firebase.firestore();
}
get uid() {
return (firebase.auth().currentUser || {}).uid;
}
get timestamp() {
return Date.now();
}
}
Fire.shared = new Fire();
export default Fire;
If you want to set the state like that you need to do it in the constructor like this:
constructor(props) {
super(props);
this.state = {
user: {}
}
}
So add that code to the top of the class and it should actually set the user to an empty object..
Everywhere else in the app you use setState....
Try to change user{} by user[]
I have a horizontal FlatList, where each time it reaches the end, it automatically adds new elements to the list, so it kind of is an infinite list. I want the app to scroll through the list by itself automatically, while the user must still be able to scroll back and forth. This is what I have to far
export default class ImageCarousel extends Component {
constructor(props) {
super(props);
this.scrollX = 0;
this.offset = new Animated.Value(0);
this.scrollTo = this.scrollTo.bind(this);
this.handleScroll = this.handleScroll.bind(this);
this.stopAnimation = this.stopAnimation.bind(this);
// Listener to call the scrollToOffset function
this.offset.addListener(this.scrollTo);
}
_scroller() {
toValue = this.scrollX + 10; // Scroll 10 pixels in each loop
this.animation = Animated.timing(
this.offset,
{
toValue: toValue,
duration: 1000, // A loop takes a second
easing: Easing.linear,
}
);
this.animation.start(() => this._scroller()); //Repeats itself when done
}
scrollTo(e) {
this.carousel.scrollToOffset({offset: e.value});
}
handleScroll(event) {
// Save the x (horizontal) value each time a scroll occurs
this.scrollX = event.nativeEvent.contentOffset.x;
}
componentDidMount() {
this._scroller();
}
render() {
return (
<View>
<FlatList
ref={el => this.carousel = el}
data={someData}
renderItem={renderFunction}
horizontal={true}
keyExtractor={someKeyFunction}
onEndReached={loadMoreElementsFunction}
onScroll={this.handleScroll}
/>
</View>
);
}
}
It works in the sense that it is automatically scrolling through the list, the problem however, is I cannot manually scroll through the list, since the scroll position is constantly updated by the scrollTo listener. I have tried to add an onPress callback to disable the animation when the FlatList is pressed, I have however not been able to get it to work.
This is my Data.
Blockquote
state = {
link: [
'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
],};
Define FlatList Ref
flatList = createRef();
FlatList component
<FlatList
style={{flex: 1}}
data={this.state.link}
keyExtractor={this._keyExtractor.bind(this)}
renderItem={this._renderItem.bind(this)}
horizontal={true}
flatListRef={React.createRef()}
ref={this.flatList}
/>
Next slide
_goToNextPage = () => {
if (CurrentSlide >= this.state.link.length-1) CurrentSlide = 0;
this.flatList.current.scrollToIndex({
index: ++CurrentSlide,
animated: true,
});
};
Start and stop Interval
_startAutoPlay = () => {
this._timerId = setInterval(this._goToNextPage, IntervalTime);
};
_stopAutoPlay = () => {
if (this._timerId) {
clearInterval(this._timerId);
this._timerId = null;
}
};
Associated function
componentDidMount() {
this._stopAutoPlay();
this._startAutoPlay();
}
componentWillUnmount() {
this._stopAutoPlay();
}
_renderItem({item, index}) {
return <Image source={{uri: item}} style={styles.sliderItems} />;
}
_keyExtractor(item, index) {
return index.toString();
}
Full Code:
import React, {Component, createRef} from 'react';
import {
Text,
View,
ScrollView,
Image,
StyleSheet,
Dimensions,
FlatList,
} from 'react-native';
let CurrentSlide = 0;
let IntervalTime = 4000;
export default class Slider extends Component {
flatList = createRef();
// TODO _goToNextPage()
_goToNextPage = () => {
if (CurrentSlide >= this.state.link.length-1) CurrentSlide = 0;
this.flatList.current.scrollToIndex({
index: ++CurrentSlide,
animated: true,
});
};
_startAutoPlay = () => {
this._timerId = setInterval(this._goToNextPage, IntervalTime);
};
_stopAutoPlay = () => {
if (this._timerId) {
clearInterval(this._timerId);
this._timerId = null;
}
};
componentDidMount() {
this._stopAutoPlay();
this._startAutoPlay();
}
componentWillUnmount() {
this._stopAutoPlay();
}
// TODO _renderItem()
_renderItem({item, index}) {
return <Image source={{uri: item}} style={styles.sliderItems} />;
}
// TODO _keyExtractor()
_keyExtractor(item, index) {
// console.log(item);
return index.toString();
}
state = {
link: [
'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
// 'https://picsum.photos/200/300',
'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
],
};
render() {
return (
<View style={{marginTop: 10, marginBottom: 10}}>
<FlatList
style={{
flex: 1,
// TODO Remove extera global padding
// marginLeft: -size.padding,
// marginRight: -size.padding,
}}
data={this.state.link}
keyExtractor={this._keyExtractor.bind(this)}
renderItem={this._renderItem.bind(this)}
horizontal={true}
flatListRef={React.createRef()}
ref={this.flatList}
/>
</View>
);
}
}
const styles = StyleSheet.create({
sliderItems: {
marginLeft: 5,
marginRight: 5,
height: 200,
width: Dimensions.get('window').width,
},
});
Just in case you're still not found the answer yet,
this is my approach to create autoscroll carousel using FlatList
import React, { Component } from 'react'
import {
StyleSheet,
View,
FlatList,
ScrollView,
Dimensions,
Image
} from 'react-native'
const { width } = Dimensions.get('window');
const height = width * 0.2844;
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
search: '',
sliderIndex: 0,
maxSlider: 2,
banners: [
{_id: 1, imageUrl: 'https://www.do-cart.com/img/slider/1.jpg'},
{_id: 2, imageUrl: 'https://www.do-cart.com/img/slider/2.jpg'},
{_id: 3, imageUrl: 'https://www.do-cart.com/img/slider/3.jpg'},
],
}
}
setRef = (c) => {
this.listRef = c;
}
scrollToIndex = (index, animated) => {
this.listRef && this.listRef.scrollToIndex({ index, animated })
}
componentWillMount() {
setInterval(function() {
const { sliderIndex, maxSlider } = this.state
let nextIndex = 0
if (sliderIndex < maxSlider) {
nextIndex = sliderIndex + 1
}
this.scrollToIndex(nextIndex, true)
this.setState({sliderIndex: nextIndex})
}.bind(this), 3000)
}
render() {
return (
<View style={styles.container}>
<View style={{height: 80, backgroundColor: '#123866', width:'100%'}}></View>
<ScrollView style={styles.scrollContainer} showsVerticalScrollIndicator={false}>
<FlatList
ref={this.setRef}
data={this.state.banners}
horizontal
showsHorizontalScrollIndicator={false}
pagingEnabled
keyExtractor={item => item._id}
renderItem={({item, i}) => (
<View key={i} style={{ height, width}}>
<Image style={{ height, width }} source={{ uri: item.imageUrl }} />
</View>
)}
onMomentumScrollEnd={(event) => {
let sliderIndex = event.nativeEvent.contentOffset.x ? event.nativeEvent.contentOffset.x/width : 0
this.setState({sliderIndex})
}}
/>
<View style={styles.sliderContainer}>
{
this.state.banners.map(function(item, index) {
return (
<View key={index} style={styles.sliderBtnContainer}>
<View style={styles.sliderBtn}>
{
this.state.sliderIndex == index ? <View style={styles.sliderBtnSelected}/> : null
}
</View>
</View>
)
}.bind(this))
}
</View>
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
scrollContainer: {
flex: 1
},
sliderContainer: {
flexDirection: 'row',
position: 'absolute',
top: 80,
alignSelf: 'center'
},
sliderBtn: {
height: 13,
width: 13,
borderRadius: 12,
borderWidth: 1,
borderColor: 'white',
alignItems: 'center',
justifyContent: 'center',
marginRight: 10
},
sliderBtnSelected: {
height: 12,
width: 12,
borderRadius: 6,
backgroundColor: 'white',
},
sliderBtnContainer: {
flexDirection: 'row', marginBottom: 24
},
});
https://snack.expo.io/rJ9DOn0Ef
For those looking for a function-based component, this is my approach. The user can interact with the carousel and the automatic scroller will simply continue from the current slide.
The trick to achieving this is using an "onViewableItemsChanged" callback, where the "itemVisiblePercentThreshold" is >= 50%. This ensures the callback fires after the scroll to the new page is more than 50% complete (otherwise the automatic scroller triggers the callback to early and makes it scroll back).
import { useCallback, useEffect, useRef, useState } from "react";
import { Dimensions } from "react-native";
import { FlatList, Image, StyleSheet } from "react-native";
const width = Dimensions.get("screen").width;
export const CarouselAutoScroll = ({ data, interval }) => {
const imageRef = useRef();
const [active, setActive] = useState(0);
const indexRef = useRef(active);
indexRef.current = active;
useInterval(() => {
if (active < Number(data?.length) - 1) {
setActive(active + 1);
} else {
setActive(0);
}
}, interval);
useEffect(() => {
imageRef.current.scrollToIndex({ index: active, animated: true });
}, [active]);
const onViewableItemsChangedHandler = useCallback(
({ viewableItems, changed }) => {
if (active != 0) {
setActive(viewableItems[0].index);
}
},
[]
);
return (
<FlatList
showsHorizontalScrollIndicator={false}
onViewableItemsChanged={onViewableItemsChangedHandler}
viewabilityConfig={{
itemVisiblePercentThreshold: 50,
}}
ref={imageRef}
pagingEnabled
data={data}
horizontal
renderItem={({ item, index }) => (
<Image
key={index}
source={item.image}
resizeMode={"contain"}
style={{
flex: 1,
height: "100%",
width: width,
}}
/>
)}
style={{ ...StyleSheet.AbsoluteFill }}
/>
);
};
const useInterval = (callback, delay) => {
const savedCallback = useRef();
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
const tick = () => {
savedCallback.current();
};
if (delay !== null) {
let id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
};