Add subobject using setState method - javascript

I'm trying to add a new subobject to an existing object using the method this.setState in a expo application. The subobject are added after a click of a button, that update the fields that compons the subobject.
This is my code:
import React, { Component } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, ImageBackground } from 'react-native';
import CenteredButton from '../components/CenteredButton';
import { Actions } from 'react-native-router-flux';
var t = require('tcomb-form-native');
var _ = require('lodash');
const Form = t.form.Form;
const stylesheet = _.cloneDeep(t.form.Form.stylesheet);
stylesheet.textbox.normal.borderColor = '#b3b3b5';
stylesheet.textbox.normal.fontFamily = 'RobotoThin';
stylesheet.textbox.normal.backgroundColor = '#fdfdfd';
stylesheet.textbox.normal.fontSize = 18;
stylesheet.textbox.normal.borderWidth = 0.6;
stylesheet.textbox.normal.borderRadius = 10;
stylesheet.textbox.error.fontFamily = 'RobotoThin';
stylesheet.textbox.error.backgroundColor = '#fdfdfd';
stylesheet.textbox.error.fontSize = 18;
stylesheet.textbox.error.borderWidth = 0.6;
stylesheet.textbox.error.borderRadius = 10;
const Email = t.refinement(t.String, email => {
const regex = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;
return regex.test(email);
});
const EmailTo = t.struct({
emailPerson: Email,
emailInsurance: t.maybe(Email)
});
const options = {
auto: 'none',
stylesheet: stylesheet,
fields: {
emailPerson: {
placeholder: 'Email personale',
autoCapitalize: 'none',
autoCorrect: false,
},
emailInsurance: {
placeholder: 'Email Assicurazione',
autoCapitalize: 'none',
password: true,
}
}
}
export default class NessunProblema extends Component {
constructor(props) {
super(props);
this.state = {
emails: {
emailPerson: '',
emailInsurance: ''
},
ascertainment: { }
}
}
componentDidMount() {
this.setState({ ascertainment: this.props.ascertainment });
}
_onChange = (emails) => {
this.setState({ emails });
}
_handle = () => {
const value = this.refs.form.getValue();
if ( value ) {
this.setState(prev => ({
ascertainment: {
...prev.ascertainment,
emails: {
...prev.ascertainment.emails,
emailPerson: value.emailPerson,
emailInsurance: value.emailInsurance
}
}
}));
}
console.log(this.state.emails);
console.log(this.state.ascertainment);
}
render() {
return (
<View style={{flex: 1, backgroundColor: 'white' }}>
<ImageBackground source={require('../images/NoProblem.png')} style={styles.backgroundImage}>
<View style={{ flex: 2, alignItems: 'center', justifyContent: 'center', width: '100%', paddingHorizontal: 20, top: 10}}>
<Text style={styles.domanda}>
Text
</Text>
<Text style={styles.domanda2}>
Text
</Text>
</View>
<View style={{padding: 20}}>
<Form
ref='form'
options={options}
type={EmailTo}
value={this.state.emails}
onChange={this._onChange}
/>
</View>
<CenteredButton
next={ this._handle }
/>
</ImageBackground>
</View>
)
}
}
const styles = StyleSheet.create({
domanda: {
color: '#00b0ff',
textAlign: 'center',
fontSize: 44,
fontFamily: 'RobotoRegular',
alignItems: 'center',
justifyContent: 'center',
padding: 20
},
domanda2: {
color: 'black',
textAlign: 'center',
fontSize: 22,
fontFamily: 'RobotoRegular',
alignItems: 'center',
justifyContent: 'center',
padding: 20
},
testoRosso: {
color: '#f32a19',
fontFamily: 'RobotoRegular',
},
backgroundImage: {
flex: 1,
resizeMode: 'cover'
},
textInput: {
width: '100%',
paddingHorizontal: 15,
height: 40,
marginBottom: 20,
fontSize: 18,
borderWidth: 0.6,
borderColor: 'black',
borderRadius: 10,
color: 'black',
fontFamily: 'RobotoThin',
backgroundColor: 'white'
},
});
I noticed that, if I click TWO times the button AVANTI I obtein the correct result. But, WHY?
I follow this answer but doens't resolve the problem.

The problem is that setState() is not synchronous, the values are updated asynchronously
setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value. There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.
_handle = () => {
const value = this.refs.form.getValue();
if ( value ) {
this.setState(prev => ({
ascertainment: {
...prev.ascertainment,
emails: {
...prev.ascertainment.emails,
emailPerson: value.emailPerson,
emailInsurance: value.emailInsurance
}
}
}));
}
console.log(this.state.emails); // will be the emails in the previous state, since setState has not been called yet by react
console.log(this.state.ascertainment); // if you click twice, you are still getting the `last` state, but since it is the same as the state you are setting the second time, you get the wrong idea that it is being set if you click twice!
}

Related

React Native and Firebase Real Time Database

I am having 2 problems using React Native and Firebase Real Time Database.
When I add something to the list with the text input, all the list itens are duplicated except the item that I just added, this problem is only solved when I refresh the app screen.
When I remove something from firebase dashboard or other client, the list is not updated real time.
import React, {useState, Component} from 'react';
import {
Text,
View,
Switch,
StyleSheet,
FlatList,
TextInput,
Button,
TouchableOpacity,
SafeAreaView,
VirtualizedList,
} from 'react-native';
import database from '#react-native-firebase/database';
class MenuBreakFastScreen extends React.Component {
state = {newItem: ''};
state = {itens: []};
componentDidMount() {
let dbRef = database().ref('/cafe/itens/');
this.listenerFirebase(dbRef);
}
listenerFirebase(dbRef) {
dbRef.on('value', dataSnapshot => {
const newItens = JSON.parse(JSON.stringify(this.state.itens));
dataSnapshot.forEach(child => {
newItens.push({
name: child.val().name,
key: child.key,
});
this.setState({itens:newItens});
});
});
}
addItem() {
if (this.state.newItem === '') {
return;
}
database().ref('/cafe/itens/').push({
name: this.state.newItem,
});
this.setState({
newItem: '',
});
}
render() {
const {itens} = this.state;
const {newItem} = this.state;
const renderItem = ( {item}) => {
return(
<ItemAsset title={item.name}/>
);
}
return (
<SafeAreaView
style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<FlatList
data={itens}
renderItem={renderItem}
keyExtractor={item => item.key}
/>
<SafeAreaView style={{flexDirection: 'row'}}>
<TextInput
style={styles.input}
onChangeText={text =>
this.setState({
newItem: text,
})
}
value={newItem}
/>
<TouchableOpacity style={styles.Botao} onPress={() => this.addItem()}>
<Text style={styles.BotaoTexto}>+</Text>
</TouchableOpacity>
</SafeAreaView>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
texto: {
fontSize: 35,
},
input: {
color: '#000',
fontSize: 22,
borderWidth: 1,
flex: 8,
margin: 10,
},
BotaoTexto: {
color: '#fff',
fontSize: 22,
},
Botao: {
backgroundColor: '#000',
marginTop: 10,
padding: 10,
flex: 1,
alignItems: 'center',
margin: 10,
},
ListaContainer: {
flexDirection: 'row',
backgroundColor: '#000',
flex: 1,
},
item: {
backgroundColor: '#000',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
flexDirection: 'row',
},
title: {
color: '#ffff',
fontSize: 32,
},
});
const ItemAsset = ( {title} ) => {
return(
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
}
export default MenuBreakFastScreen;
When you are listen for real time changes on real-time database it will send all the items with snapshot when any data is changed. That happens because you are listen for whole list, not only for a single item. Therefore you do not need to get the current list from state. You just have to set the state with retrieved data.
listenerFirebase(dbRef) {
dbRef.on('value', dataSnapshot => {
const newItens = []; // This should be initially empty array. That's all.
dataSnapshot.forEach(child => {
newItens.push({
name: child.val().name,
key: child.key,
});
});
this.setState({itens:newItens});
});
}
After correcting this part the error you got when removing data will be also resolved.

React Native: Touchable Opacity element is clickable on iOS but not Android

I'm working on a React Native app with a typeahead component. The typeahead displays options that overlay other content on the route (see right image below). When a user clicks one of those options, an onPress listener runs a function:
This all works just fine on iOS. On Android though, the onPress event is never received. Even more strangely, when I try to click on an option lower in the list (like Boston, MA, USA), the onPress event is received by the card below the pressed option (Djerba).
Does anyone know what might cause this behavior? I'd be super grateful for any insights others can offer on this query.
Here's the code for the Explore view and the typeahead components.
Explore.js
import React from 'react'
import { connect } from 'react-redux'
import { Text, View, ScrollView, TouchableOpacity } from 'react-native'
import { gradients, sizing } from '../../style'
import { LinearGradient } from 'expo-linear-gradient'
import { MountainHero } from '../Heros'
import { CardRow } from '../Card'
import Loading from '../Loading'
import { setExploreSearch, onExploreTypeaheadClick } from '../../actions/locations'
import { Typeahead } from '../Typeahead'
const styles = {
container: {
flex: 1,
flexDirection: 'column',
},
scrollView: {
paddingBottom: sizing.margin,
},
loadingContainer: {
position: 'absolute',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
zIndex: 100,
elevation: 100,
top: 53,
width: '100%',
},
typeahead: {
margin: sizing.margin,
marginBottom: 0,
width: sizing.screen.width - (2*sizing.margin),
zIndex: 100,
elevation: 100,
}
}
const Explore = props => {
const { authenticated: a, spotlight, loading } = props;
let r = (a.recommendedLocations || []);
if (!r || !spotlight) return null;
// remove spotlight locations from the recommended locations
const ids = spotlight.map(i => i.guid);
const recommended = r.filter(i => ids.indexOf(i.guid) == -1);
return (
<LinearGradient style={styles.container} colors={gradients.teal}>
<ScrollView contentContainerStyle={styles.scrollView}>
{loading && (
<View style={styles.loadingContainer}>
<Loading />
</View>
)}
<MountainHero text='Explore' />
<Typeahead
style={styles.typeahead}
placeholder='Search Cities'
value={props.exploreSearch}
onChange={props.setExploreSearch}
vals={props.exploreTypeahead}
valKey={'place_id'}
onTypeaheadClick={props.onExploreTypeaheadClick}
/>
<CardRow
text='Explore Places'
cards={recommended}
type='location' />
<CardRow
text='In the Spotlight'
cards={spotlight}
type='location' />
</ScrollView>
</LinearGradient>
)
}
const mapStateToProps = state => ({
authenticated: state.users.authenticated,
spotlight: state.locations.spotlight,
exploreSearch: state.locations.exploreSearch,
exploreTypeahead: state.locations.exploreTypeahead,
loading: state.locations.loading,
})
const mapDispatchToProps = dispatch => ({
setExploreSearch: s => dispatch(setExploreSearch(s)),
onExploreTypeaheadClick: val => dispatch(onExploreTypeaheadClick(val)),
})
export default connect(mapStateToProps, mapDispatchToProps)(Explore)
Typeahead.js
import React from 'react'
import { Text, View, TouchableOpacity } from 'react-native'
import { sizing, GradientInput } from '../style'
const styles = {
container: {
position: 'absolute',
zIndex: 100,
elevation: 100,
height: 400,
width: '100%',
},
input: {
width: '100%',
borderRadius: 0,
},
typeaheadContainer: {
position: 'absolute',
zIndex: 100,
elevation: 100,
top: 55,
width: '100%',
},
typeaheadRow: {
padding: 10,
paddingTop: 12,
paddingBottom: 12,
borderWidth: 1,
borderColor: '#eeeeee',
backgroundColor: '#ffffff',
marginBottom: -1,
},
typeaheadRowText: {
fontSize: 15,
fontFamily: 'open-sans',
lineHeight: 20,
backgroundColor: '#ffffff',
},
}
export const Typeahead = props => {
return (
<View style={[props.container, props.style]}>
<GradientInput style={styles.input}
placeholder={props.placeholder}
value={props.value}
onChange={props.onChange} />
<TypeaheadList vals={props.vals}
valKey={props.valKey}
onTypeaheadClick={props.onTypeaheadClick} />
</View>
)
}
export const TypeaheadList = props => {
if (!props.vals) return null;
return (
<View style={styles.typeaheadContainer}>
{props.vals.map(i => {
let text = i.text;
if (text.length > 31) text = text.substring(0,31) + '...';
return (
<TouchableOpacity activeOpacity={0.5} key={i[props.valKey]}
style={styles.typeaheadRow}
onPress={() => props.onTypeaheadClick(i[props.valKey])}>
<Text numberOfLines={1} style={styles.typeaheadRowText}>{text}</Text>
</TouchableOpacity>
)
})}
</View>
)
}
export default Typeahead
Try to move Typeahead component below all CardRow components and set position:absolute for Typeahead. Probably on android - the latest view shadow all views before (I am not sure, but I think you have to try it for next discovering issue).
You should also remove position: absolute from all but one component. Working code:
Explore.js
import React from 'react'
import { connect } from 'react-redux'
import { Text, View, ScrollView, TouchableOpacity } from 'react-native'
import { gradients, sizing } from '../../style'
import { LinearGradient } from 'expo-linear-gradient'
import { MountainHero } from '../Heros'
import { CardRow } from '../Card'
import Loading from '../Loading'
import { setExploreSearch, onExploreTypeaheadClick } from '../../actions/locations'
import { Typeahead } from '../Typeahead'
const styles = {
container: {
flex: 1,
flexDirection: 'column',
},
scrollView: {
paddingBottom: sizing.margin,
},
loadingContainer: {
position: 'absolute',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
zIndex: 1,
elevation: 1,
top: 53,
width: '100%',
},
topCardRow: {
paddingTop: sizing.margin + sizing.gradientInput.height,
},
typeahead: {
margin: sizing.margin,
marginBottom: 0,
width: sizing.screen.width - (2*sizing.margin),
zIndex: 1,
elevation: 1,
position: 'absolute',
top: sizing.mountainHero.height,
left: 0,
}
}
const Explore = props => {
const { authenticated: a, spotlight, loading } = props;
let r = (a.recommendedLocations || []);
if (!r || !spotlight) return null;
// remove spotlight locations from the recommended locations
const ids = spotlight.map(i => i.guid);
const recommended = r.filter(i => ids.indexOf(i.guid) == -1);
return (
<LinearGradient style={styles.container} colors={gradients.teal}>
<ScrollView contentContainerStyle={styles.scrollView}>
{loading && (
<View style={styles.loadingContainer}>
<Loading />
</View>
)}
<MountainHero text='Explore' />
<CardRow
style={styles.topCardRow}
text='Explore Places'
cards={recommended}
type='location' />
<CardRow
text='In the Spotlight'
cards={spotlight}
type='location' />
<Typeahead
style={styles.typeahead}
placeholder='Search Cities'
value={props.exploreSearch}
onChange={props.setExploreSearch}
vals={props.exploreTypeahead}
valKey={'place_id'}
onTypeaheadClick={props.onExploreTypeaheadClick}
/>
</ScrollView>
</LinearGradient>
)
}
const mapStateToProps = state => ({
authenticated: state.users.authenticated,
spotlight: state.locations.spotlight,
exploreSearch: state.locations.exploreSearch,
exploreTypeahead: state.locations.exploreTypeahead,
loading: state.locations.loading,
})
const mapDispatchToProps = dispatch => ({
setExploreSearch: s => dispatch(setExploreSearch(s)),
onExploreTypeaheadClick: val => dispatch(onExploreTypeaheadClick(val)),
})
export default connect(mapStateToProps, mapDispatchToProps)(Explore)
Typeahead.js
import React from 'react'
import { Text, View, TouchableOpacity } from 'react-native'
import { sizing, GradientInput } from '../style'
const styles = {
container: {
zIndex: 1,
elevation: 1,
height: 400,
width: '100%',
},
input: {
width: '100%',
borderRadius: 0,
},
typeaheadContainer: {
zIndex: 1,
elevation: 1,
top: 0,
width: '100%',
},
typeaheadRow: {
padding: 10,
paddingTop: 12,
paddingBottom: 12,
borderWidth: 1,
borderColor: '#eeeeee',
backgroundColor: '#ffffff',
marginBottom: -1,
zIndex: 1,
elevation: 1,
},
typeaheadRowText: {
fontSize: 15,
fontFamily: 'open-sans',
lineHeight: 20,
backgroundColor: '#ffffff',
},
}
export const Typeahead = props => {
return (
<View style={[props.container, props.style]}>
<GradientInput style={styles.input}
placeholder={props.placeholder}
value={props.value}
onChange={props.onChange} />
<TypeaheadList vals={props.vals}
valKey={props.valKey}
onTypeaheadClick={props.onTypeaheadClick} />
</View>
)
}
export const TypeaheadList = props => {
if (!props.vals) return null;
return (
<View style={styles.typeaheadContainer}>
{props.vals.map(i => {
let text = i.text;
if (text.length > 31) text = text.substring(0,31) + '...';
return (
<TouchableOpacity activeOpacity={0.5} key={i[props.valKey]}
style={styles.typeaheadRow}
onPress={() => props.onTypeaheadClick(i[props.valKey])}>
<Text numberOfLines={1} style={styles.typeaheadRowText}>{text}</Text>
</TouchableOpacity>
)
})}
</View>
)
}
export default Typeahead

react-native: `this.state` is undefined in login function

I'm having trouble accessing this.state in functions inside my component.
Always I get "Undefined is not a object this.state.username, this.state.password" error
SimpleForm.js
import Expo from 'expo';
import React from 'react';
import { StackNavigator, DrawerNavigator } from 'react-navigation';
import App from './App';
import RegisterForm from './register';
import { View, Text, TextInput, Image, TouchableOpacity, AsyncStorage, StyleSheet } from 'react-native';
import { YourRestApi } from './constants/api3';
class SimpleForm extends React.Component {
constructor(props) {
super(props);
this.state = { username: '', password: '', datas: '' };
this.login = this.login.bind(this, this.state.username, this.state.password);
}
componentWillMount() {
this.login();
}
registerscreen = () => {
this.props.navigation.navigate('Register');
}
login() {
YourRestApi(this.state.username, this.state.password)
.then((response) => {
console.log(response.success);
this.setState({ loading: false, datas: response });
});
if (this.state.datas.success === true) {
const info = this.state.datas.message;
AsyncStorage.setItem('info', JSON.stringify(info));
this.props.navigation.navigate('SecondScreen');
} else {
alert(this.state.datas.message);
}
}
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Image source={require('./assets/img/sd.png')} style={styles.backgroundImage}>
<View style={styles.content}>
<Text style={styles.logo}>Toto Prediction </Text>
<View style={styles.inputContainer}>
<TextInput
underlineColorAndroid='transparent' style={styles.input}
onChangeText={(username) => this.setState({ username })}
value={this.state.username} placeholder='username'
/>
<TextInput
secureTextEntry underlineColorAndroid='transparent' style={styles.input}
onChangeText={(password) => this.setState({ password })}
value={this.state.password} placeholder='password'
/>
</View>
<TouchableOpacity onPress={this.login} style={styles.buttonContainer}>
<Text style={styles.buttonText}>Login</Text>
</TouchableOpacity>
this._onPressGet.bind(this)
<TouchableOpacity onPress={this.registerscreen} style={styles.buttonContainer}>
<Text style={styles.buttonText}>Register</Text>
</TouchableOpacity>
</View>
</Image>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
backgroundImage: {
flex: 1,
alignSelf: 'stretch',
width: null,
justifyContent: 'center',
},
content: {
alignItems: 'center',
},
logo: {
color: 'white',
fontSize: 40,
fontStyle: 'italic',
fontWeight: 'bold',
textShadowColor: '#252525',
textShadowOffset: { width: 2, height: 2 },
textShadowRadius: 15,
marginBottom: 20,
},
inputContainer: {
margin: 20,
marginBottom: 0,
padding: 20,
paddingBottom: 10,
alignSelf: 'stretch',
borderWidth: 1,
borderColor: '#fff',
backgroundColor: 'rgba(255,255,255,0.2)',
},
input: {
fontSize: 16,
height: 40,
padding: 10,
marginBottom: 10,
backgroundColor: 'rgba(255,255,255,1)',
},
buttonContainer: {
margin: 20,
padding: 20,
backgroundColor: 'blue',
borderWidth: 1,
borderColor: '#fff',
backgroundColor: 'rgba(255,255,255,0.6)',
},
buttonText: {
fontSize: 16,
fontWeight: 'bold',
textAlign: 'center',
},
});
const SimpleApp = DrawerNavigator({
Onescreen: { screen: SimpleForm },
SecondScreen: { screen: App },
Register: { screen: RegisterForm },
});
Expo.registerRootComponent(SimpleApp);
Api3.js
export function YourRestApi(username1, password1) {
fetchlogin(username1, password1);
}
function fetchlogin(username1, password1) {
const details = {
username: username1,
password: password1,
};
const formBody = Object.keys(details).map(key => `${encodeURIComponent(key)}=${encodeURIComponent(details[key])}`).join('&');
fetch('https://*********************', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
},
body: formBody,
})
.then((response) => response.json())
.then((response) => {
console.log('requestAppInstallation success ', response);
return response;
})
.done();
}
I tried binding login to this.state but doesnt worked
I already checked other questions but nothing is worked
Any idea what could be causing this ?
In your constructor replace the binding statement like below
constructor(props) {
super(props);
this.state = { username: '', password: '', datas: '' };
this.login = this.login.bind(this);
}
Your login function should be bound in order for it to access the correct this if passed to a Touchable.
Could be fixed by either one of these ways:
<TouchableOpacity onPress={this.login.bind(this)} ...>
OR:
<TouchableOpacity onPress={() => this.login()} ...>
It is basically nothing but just an error returned by firebase in case user enters wrongly formatted email. Try entering rightly formatted email id in the signup or login form and you will not get that error from firebase.
Firebase basically checks at its end whether user entered correct mail id or not while creating new user.

React Native Navigator - screen always blank

I am trying to follow the example (https://github.com/facebook/react-native/tree/master/Examples/UIExplorer/Navigator) on the react native site to set up my navigator, but I can't seem to get it to work. No matter what I seem to do, the GoogSignIn scene always comes up blank although it does hit both of my console.log points in the file. I have tried switching the starting point to a different scene in my app, but the same thing always happens. I assume this is something I did wrong in index.ios.js with my navigator, but I'm not sure what. Any help is much appreciated.
index.ios.js
'use strict';
var React = require('react-native');
var DataEntry = require('./app/DataEntry');
var PasswordView = require('./app/PasswordView');
var GoogSignIn = require('./app/GoogSignIn');
var {
AppRegistry,
Image,
StyleSheet,
Text,
View,
Navigator,
TouchableOpacity,
} = React;
class PasswordRecovery extends React.Component {
render() {
return (
<Navigator
ref={this._setNavigatorRef}
style={styles.container}
initialRoute={{id: 'GoogSignIn', name: 'Index'}}
renderScene={this.renderScene}
configureScene={(route) => {
if (route.sceneConfig) {
return route.sceneConfig;
}
return Navigator.SceneConfigs.FloatFromRight;
}} />
);
}
renderScene(route, navigator) {
switch (route.id) {
case 'GoogSignIn':
return <GoogSignIn navigator={navigator} />;
case 'DataEntry':
return <DataEntry navigator={navigator} />;
case 'PasswordView':
return <PasswordView navigator={navigator} />;
default:
return this.noRoute(navigator);
}
noRoute(navigator) {
return (
<View style={{flex: 1, alignItems: 'stretch', justifyContent: 'center'}}>
<TouchableOpacity style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}
onPress={() => navigator.pop()}>
<Text style={{color: 'red', fontWeight: 'bold'}}>ERROR: NO ROUTE DETECTED</Text>
</TouchableOpacity>
</View>
);
}
_setNavigatorRef(navigator) {
if (navigator !== this._navigator) {
this._navigator = navigator;
if (navigator) {
var callback = (event) => {
console.log(
`TabBarExample: event ${event.type}`,
{
route: JSON.stringify(event.data.route),
target: event.target,
type: event.type,
}
);
};
// Observe focus change events from the owner.
this._listeners = [
navigator.navigationContext.addListener('willfocus', callback),
navigator.navigationContext.addListener('didfocus', callback),
];
}
}
}
componentWillUnmount() {
this._listeners && this._listeners.forEach(listener => listener.remove());
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('PasswordRecovery', () => PasswordRecovery);
I am just trying to get this all setup so that I can display a Google Sign in scene and then navigate from there. The code for that scene so far is here:
GoogSignIn.js
'use strict';
var React = require('react-native');
var { NativeAppEventEmitter } = require('react-native');
var GoogleSignin = require('react-native-google-signin');
var cssVar = require('cssVar');
var { Icon } = require('react-native-icons');
var {
AppRegistry,
StyleSheet,
Text,
View,
TouchableOpacity,
TouchableHighlight,
PixelRatio,
Navigator,
} = React;
var NavigationBarRouteMapper = {
LeftButton: function(route, navigator, index, navState) {
if (index === 0) {
return null;
}
var previousRoute = navState.routeStack[index - 1];
return (
<TouchableOpacity
onPress={() => navigator.pop()}
style={styles.navBarLeftButton}>
<Text style={[styles.navBarText, styles.navBarButtonText]}>
{previousRoute.title}
</Text>
</TouchableOpacity>
);
},
RightButton: function(route, navigator, index, navState) {
return (
null
);
},
Title: function(route, navigator, index, navState) {
return (
<Text style={[styles.navBarText, styles.navBarTitleText]}>
GOOGLE SIGN IN
</Text>
);
},
};
class GoogSignin extends React.Component {
constructor(props) {
super(props);
this.state = {
user: null
};
}
componentWillMount() {
var navigator = this.props.navigator;
var callback = (event) => {
console.log(
`NavigationBarSample : event ${event.type}`,
{
route: JSON.stringify(event.data.route),
target: event.target,
type: event.type,
}
);
};
// Observe focus change events from this component.
this._listeners = [
navigator.navigationContext.addListener('willfocus', callback),
navigator.navigationContext.addListener('didfocus', callback),
];
}
componentWillUnmount() {
this._listeners && this._listeners.forEach(listener => listener.remove());
}
componentDidMount() {
this._configureOauth(
'105558473349-7usegucirv10bruohtogd0qtuul3kkhn.apps.googleusercontent.com'
);
}
renderScene(route, navigator) {
console.log("HERE");
return (
<View style={styles.container}>
<TouchableHighlight onPress={() => {this._signIn(); }}>
<View style={{backgroundColor: '#f44336', flexDirection: 'row'}}>
<View style={{padding: 12, borderWidth: 1/2, borderColor: 'transparent', borderRightColor: 'white'}}>
<Icon
name='ion|social-googleplus'
size={24}
color='white'
style={{width: 24, height: 24}}
/>
</View>
<Text style={{color: 'white', padding: 12, marginTop: 2, fontWeight: 'bold'}}>Sign in with Google</Text>
</View>
</TouchableHighlight>
</View>
);
}
render() {
return (
<Navigator
debugOverlay={false}
style={styles.container}
renderScene={this.renderScene}
navigationBar={
<Navigator.NavigationBar
routeMapper={NavigationBarRouteMapper}
style={styles.navBar}/>
}/>
);
}
_configureOauth(clientId, scopes=[]) {
console.log("WE HERE")
GoogleSignin.configure(clientId, scopes);
NativeAppEventEmitter.addListener('googleSignInError', (error) => {
console.log('ERROR signin in', error);
});
NativeAppEventEmitter.addListener('googleSignIn', (user) => {
console.log(user);
this.setState({user: user});
});
return true;
}
_signIn() {
GoogleSignin.signIn();
}
_signOut() {
GoogleSignin.signOut();
this.setState({user: null});
}
};
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
messageText: {
fontSize: 17,
fontWeight: '500',
padding: 15,
marginTop: 50,
marginLeft: 15,
},
button: {
backgroundColor: 'white',
padding: 15,
borderBottomWidth: 1 / PixelRatio.get(),
borderBottomColor: '#CDCDCD',
},
buttonText: {
fontSize: 17,
fontWeight: '500',
},
navBar: {
backgroundColor: 'white',
},
navBarText: {
fontSize: 16,
marginVertical: 10,
},
navBarTitleText: {
color: cssVar('fbui-bluegray-60'),
fontWeight: '500',
marginVertical: 9,
},
navBarLeftButton: {
paddingLeft: 10,
},
navBarRightButton: {
paddingRight: 10,
},
navBarButtonText: {
color: cssVar('fbui-accent-blue'),
},
scene: {
flex: 1,
paddingTop: 20,
backgroundColor: '#EAEAEA',
},
});
module.exports = GoogSignin;
edit: screenshots of inspector:
In your renderScene method, try doing something like this (this will also help you remove that big switch):
Component = route.id
<View style={styles.container}>
<Component navigator={navigator} route={route} />
</View>
styles = StyleSheet.create({
container:
flex: 1
})

React Native progress bar percentage not staying the same after closing the app

Every time I press a button the progress bar will go up %20 but the problem is for instance if its at %80 and I reload the app it will show it as %60 instead, I was wondering if anyone could help me fix this issue to have the progress bars percentage stay the same after reloading or closing the app.
'use strict';
var React = require('react-native');
var ProgressBar = require('react-native-progress-bar');
var {
AppRegistry,
AsyncStorage,
StyleSheet,
Text,
View,
TouchableHighlight
} = React;
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FFF',
},
button: {
alignSelf: 'center',
marginTop: 50,
width: 100,
height: 50,
backgroundColor: '#0059FF',
borderRadius: 8,
borderWidth: 2,
borderColor: '#0059FF'
},
buttonClear: {
alignSelf: 'center',
marginTop: 10,
width: 100,
height: 50,
backgroundColor: '#3B3A3A',
borderRadius: 8,
borderWidth: 2,
borderColor: '#3B3A3A'
},
buttonText: {
fontSize: 18,
textAlign: 'center',
lineHeight: 33,
color: '#FFF',
}
});
var PROGRESS = 0;
class BasicStorageExample extends React.Component {
constructor(props) {
super(props);
this.state = {
progress: PROGRESS
}
}
componentDidMount() {
AsyncStorage.getItem('progressbar')
.then((value) => {
JSON.parse(value);
this.setState({
progress: value
});
console.log('Progress on load: ' + value);
})
.done();
}
onButtonPress() {
AsyncStorage.setItem('progressbar', JSON.stringify(PROGRESS))
.then(() => {
JSON.parse(PROGRESS);
this.setState({
progress: PROGRESS += 0.2
});
console.log('Progress on Button Press: ' + PROGRESS);
})
.done();
}
onButtonClearPress() {
AsyncStorage.setItem('progressbar', JSON.stringify(PROGRESS))
.then(() => {
JSON.parse(PROGRESS);
PROGRESS = 0;
this.setState({
progress: 0
});
})
.done();
}
render() {
return (
<View style={styles.container}>
<ProgressBar
fillStyle={{}}
backgroundStyle={{backgroundColor: '#cccccc', borderRadius: 2}}
style={{marginTop: 10, width: 300}}
progress={this.state.progress} />
<TouchableHighlight
ref="button"
style={styles.button}
underlayColor='#002C7F'
onPress={this.onButtonPress.bind(this)}>
<Text style={styles.buttonText}>Done</Text>
</TouchableHighlight>
<TouchableHighlight
style={styles.buttonClear}
underlayColor='#002C7F'
onPress={this.onButtonClearPress.bind(this)}>
<Text style={styles.buttonText}>Clear</Text>
</TouchableHighlight>
</View>
);
}
};
AppRegistry.registerComponent('BasicStorageExample', () => BasicStorageExample);
The problem is that you are getting the old value of PROGRESS (before you increment by 0.2) and setting this value to the item progressbar.
So, every time you reload, React runs the componentDidMount function, and since you set progressbar to the old value of PROGRESS, it will always show it one increment behind what you see in the view.
Try changing your onButtonPress() to this:
onButtonPress() {
PROGRESS += 0.2;
AsyncStorage.setItem('progressbar', JSON.stringify(PROGRESS))
... // continues normally

Categories