react-native Swiper is blank inside a modal - javascript

i use react-native and react-native-swiper
Which OS ?
Android
Version
Which versions are you using:
react-native-swiper v1.5.13?
react-native v0.51.0
Actual behaviour
I display a Modal with swiper inside it. I get a blank display, only the button of the swiper but not the content
Expected behaviour
To show the content of the swiper inside a modal
How to reproduce it>
I tryed to reproduce the bug with a very simplified version of my code
try it in snack
https://snack.expo.io/rk8rb3ZzM
or my code
import React, { Component } from "react";
import { Text, View, Modal, Dimensions } from "react-native";
import Swiper from "react-native-swiper"; // 1.5.13
import { Button } from "react-native-elements"; // 0.18.5
import "#expo/vector-icons"; // 6.2.1
var width = Dimensions.get("window").width;
var height = Dimensions.get("window").height;
export default class extends Component {
constructor(props) {
super(props);
this.state = {
items:[
{ title: "Hello Swiper", css: thisstyles.slide1 },
{ title: "Beautiful", css: thisstyles.slide2 },
{ title: "simple", css: thisstyles.slide3 },
{ title: "And simple", css: thisstyles.slide3 }
],
modalVisible: false
};
}
componentDidMount() {
}
// affiche / cache la modal avec l'image en plein écran
toggleModalVisible = () => {
this.setState({ modalVisible: !this.state.modalVisible });
};
// vue plein écran avec zoom sans info
renderFullScreen() {
if (!this.state.modalVisible) {
return null;
}
return (
<Modal
animationType={"slide"}
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => this.toggleModalVisible()}
>
<View style={thisstyles.modalFullScreen}>
<Text>I have component and text here</Text>
<Swiper style={thisstyles.wrapper} showsButtons={true}>
{this.state.items.map((item, key) => {
console.log("item", item);
return (
<View key={key} style={item.css}>
<Text style={thisstyles.text}>{item.title}</Text>
</View>
);
})}
</Swiper>
</View>
</Modal>
);
}
render() {
return (
<Swiper style={thisstyles.wrapper} showsButtons={true}>
{this.state.items.map((item, key) => {
console.log("item", item);
return (
<View key={key} style={item.css}>
<Text style={thisstyles.text}>{item.title}</Text>
{this.renderFullScreen()}
<Button
title="modal"
onPress={() => this.toggleModalVisible()}
icon={{ name: "close", type: "font-awesome" }}
/>
</View>
);
})}
</Swiper>
);
}
}
const thisstyles = {
modalFullScreen: {
height: height,
width: width
},
wrapper: {},
slide1: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#9DD6EB"
},
slide2: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#97CAE5"
},
slide3: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#92BBD9"
},
text: {
color: "black",
fontSize: 30,
fontWeight: "bold"
}
};
Steps to reproduce
run the app
click on the button "x modal"

I had to add a delay to get mine to work, but yes it works!
constructor(props) {
super(props);
this.state = { showSwiper: false };
}
componentDidMount() {
// Must use this 100-ms delayed swiper workaround to render on Android properly
setTimeout(() => {
this.setState({showSwiper: true});
}, 100);
}
render() {
var exampleSwiper = (
<Swiper activeDotColor={'white'} loop={false} >
<View style={{width: 100, height: 100, backgroundColor: 'white'}} />
<View style={{width: 100, height: 100, backgroundColor: 'white'}} />
<View style={{width: 100, height: 100, backgroundColor: 'white'}} />
</Swiper>
);
return (
<Modal presentationStyle={'overFullScreen'}>
{this.state.showSwiper ? exampleSwiper : null}
</Modal>
);
}

Create one parent View tag and set its height based on your requirement. For example:
<View style={{height:'50%'}}>
<Swiper {....} />
</View>

Related

Passing style to my custom component is not working in react native. (styles are not attached to my custom component)

I am new to react native.
I created some custom components in project. And I pass some style to them via the props but my passing styles are not attached to that components. At the first it was working correctly but suddenly I don't know what happened that my passing styles are not working.
Here is my code:
This the page where I used my custom component and passed style to that.
function StartGameScreen(props) {
const [confirmed, setConfirmed] = useState(false);
const [selectedNumber, setSelectedNumber] = useState();
const numInputHandler = (inputText) => {
setEneteredValue(inputText.replace(/[^0-9]/g, ""));
};
const confirmInput = () => {
const chosenNumber = parseInt(enteredValue);
if (isNaN(chosenNumber) || chosenNumber <= 0 || chosenNumber > 99) {
Alert.alert(
"Invalid number!",
"Number has to be a number between 0 and 99.",
[{ text: "Okay", style: "destructive", onPress: resetInput }]
);
return;
}
setConfirmed(true);
setSelectedNumber(chosenNumber);
setEneteredValue("");
Keyboard.dismiss();
};
let confirmedOutput;
if (confirmed) {
confirmedOutput = (
<Card style={styles.summeryContainer}>
<Text>You selected</Text>
<NumberContainer>{selectedNumber}</NumberContainer>
<Button
title="START GAME"
onPress={() => {
console.log("hello" + selectedNumber);
props.onStartGame(selectedNumber);
}}
/>
</Card>
);
}
return (
<TouchableWithoutFeedback
onPress={() => {
Keyboard.dismiss();
}}
>
<View style={styles.container}>
<Text style={styles.title}>Start A New Game!</Text>
*This is where I used my custom component (<Card>).*
<Card style={styles.inputContainer}>
<Text>select a number</Text>
<Input
style={styles.input}
blurOnSubmit
autoCapatilize="none"
autoCorrect={false}
keyboardType="number-pad"
maxLength={2}
onChangeText={numInputHandler}
value={enteredValue}
/>
<View style={styles.buttonCon}>
<View style={styles.button}>
<Button
title="Reset"
color={Colors.accent}
onPress={resetInput}
/>
</View>
<View style={styles.button}>
<Button
title="Confirm"
color={Colors.primary}
onPress={confirmInput}
/>
</View>
</View>
</Card>
{confirmedOutput}
</View>
</TouchableWithoutFeedback>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 10,
alignItems: "center",
},
inputContainer: {
width: 300,
maxWidth: "80%",
alignItems: "center",
},
input: {
textAlign: "center",
width: 50,
},
});
export default StartGameScreen;
And this is my Card custom component:
function Card(props) {
return (
<View style={{ ...styles.container, ...props.style }}>
{props.children}
</View>
);
}
const styles = StyleSheet.create({
container: {
shadowColor: "black",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.26,
shadowRadius: 6,
elevation: 12,
backgroundColor: "white",
padding: 20,
borderRadius: 10,
},
});
export default Card;
Change Your Card component like below then it will work
function Card(props) {
return (
<View style={[styles.container,props.style]}>
{props.children}
</View>
);
}

Why always open Modal by default while opening a Screen in React-Native?

In my React-Native project, I want to use Modal inside render. I have declared one state variable like below-
this.state = {
ModalVisibleStatus: false
};
For showing the Modal I have declared a function-
ShowModalFunction(visible) {
this.setState({ModalVisibleStatus: visible});
}
And inside the render function I have just write show a Modal like below on a Button Press-
<Modal
transparent={false}
animationType={"slide"}
visible={this.state.ModalVisibleStatus}
onRequestClose={ () => { this.ShowModalFunction(!this.state.ModalVisibleStatus)} } >
<View style={{ flex:1, justifyContent: 'center', alignItems: 'center' }}>
<View style={styles.ModalInsideView}>
{/* Put All Your Components Here, Which You Want To Show Inside The Modal. */}
<Text style={styles.TextStyle}>Text Component With Some Sample Text In Modal. </Text>
<Button title="Click Here To Hide Modal" onPress={() => { this.ShowModalFunction(!this.state.ModalVisibleStatus)} } />
{/* Put All Your Components Here, Which You Want To Show Inside The Modal. */}
</View>
</View>
</Modal>
Now, the thing is whenever I start the Screen by default the Modal remains open. But I have declared the variable ModalVisibleStatus to false initially.
Here's the entire code of My Class-
HelloWorldApp.js
i
mport React, { Component } from 'react';
import {
Text, View, ScrollView, StyleSheet, Image, TextInput, NetInfo, TouchableOpacity,
TouchableHighlight, AsyncStorage, Modal, Alert, Button
} from 'react-native';
import { ICON_NOTE, ICON_TODO, ICON_TAG, ICON_REMINDER, ICON_URGENT, ICON_OFFICE, ICON_PERSONAL, ICON_WORK } from '../actions/ActionTypes';
import LoginScreen from '../components/LoginScreen';
export default class HelloWorldApp extends Component {
state = {
isLoading: false,
getValue: null,
ModalVisibleStatus: false
}
constructor() {
super();
this.state = {
title: '',
details: '',
timestamp: '',
status: '',
url: '',
mail: '',
phone: '',
category: '',
showLoader: false,
showAlert: false,
isNetConnected: true,
catImage: null,
}
};
updateImage(image, category) {
this.setState({
catImage: image,
category: category
})
}
updateValue(text, field) {
if (field == 'title') {
this.setState({
title: text
})
}
else if (field == 'details') {
this.setState({
details: text
})
}
}
ShowModalFunction(visible) {
this.setState({ ModalVisibleStatus: visible });
}
// net connection starts
async componentDidMount() {
const token = await AsyncStorage.getItem('token');
this.setState({ getValue: token });
}
render() {
console.log('#ZZZ2:', this.state.getValue);
return (
<View style={{ flex: 1 }}>
<ScrollView keyboardShouldPersistTaps={'handled'}>
<View style={styles.container}>
<View style={styles.inputContainerEmail}>
<Image style={styles.inputIcon} source={{ uri: this.state.catImage }} />
<TextInput style={styles.inputs}
placeholder="Title"
keyboardType="email-address"
underlineColorAndroid='transparent'
onChangeText={(text) => this.updateValue(text, 'title')} />
</View>
<View style={styles.inputContainerDetails}>
<TextInput style={styles.inputs}
placeholder="Details"
multiline
underlineColorAndroid='transparent'
onChangeText={(text) => this.updateValue(text, 'details')} />
</View>
<ScrollView horizontal={true}>
<View style={{ flexDirection: 'row', flex: 1, marginTop: 10, marginBottom: 10, marginRight: 20, marginLeft: 10 }}>
<TouchableOpacity style={{ justifyContent: 'center', alignItems: 'center', marginRight: 10 }}
onPress={() => { this.updateImage(ICON_NOTE, '1') }}>
<Image style={styles.inputIconCategory} source={{ uri: ICON_NOTE }} />
<Text style={{ marginLeft: 25, marginTop: 5 }}>Note</Text>
</TouchableOpacity>
</View>
</ScrollView>
<TouchableOpacity style={styles.buttonContainerRegister}
onPress={() => {
console.log("#Ctegory:" + this.state.category + "\n Token:" + this.state.getValue + "\nTitle:" + this.state.title + "\nDetails:" + this.state.details + "\Timestamp:" + this.state.timestamp)
}}
>
<Text>Save</Text>
</TouchableOpacity>
<Modal
transparent={false}
animationType={"slide"}
visible={this.state.ModalVisibleStatus}
onRequestClose={() => { this.ShowModalFunction(!this.state.ModalVisibleStatus) }} >
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<View style={styles.ModalInsideView}>
<Text style={styles.TextStyle}>Text Component With Some Sample Text In Modal. </Text>
<Button title="Click Here To Hide Modal" onPress={() => { this.ShowModalFunction(!this.state.ModalVisibleStatus) }} />
{/* Put All Your Components Here, Which You Want To Show Inside The Modal. */}
</View>
</View>
</Modal>
<Button onPress={() => { this.ShowModalFunction(true) }} title="Click Here To Show Modal" />
</View>
</ScrollView>
</View>
);
}
}
So, I want a solution to make the modal closed by default and open it when I click the Button.
That's because it's value is getting undefined. You need to define all states in the constructor.
isLoading:false,
getValue: null,
ModalVisibleStatus: false
cut these var's from state={...}and put them inside the this.state in constructor.
Add ModalVisibleStatus: false into your constructor and cut it from the state
constructor() {
super();
this.state = {
title:'',
details:'',
timestamp : '',
status: '',
url:'',
mail:'',
phone:'',
category:'',
showLoader:false,
showAlert: false,
isNetConnected: true,
catImage: null,
ModalVisibleStatus: false
}
};
put ModalVisibleStatus: false in this.state like this
this.state{
ModalVisibleStatus: false}
I believe that will work.
ShowModalFunction() {
this.setState({
ModalVisibleStatus: !this.state.ModalVisibleStatus
});
}

E-commerce like feature for selecting product sizes or color

I have searched the whole web to the best of my ability on how to create an interface for selecting products just like the ones implemented in most of the major e-commerce apps(amazon,taobao,shopify..).The goal is to highlight or change the styles of the selected item in the list by simultaneously removing the styles of the previously selected item. I am trying to use react-native to clone such a feature. Any references or guides on how to do this will be highly appreciated!
import React, { Component } from 'react';
import { View, Text ,StyleSheet, TouchableOpacity, } from 'react-native';
class Selections extends Component {
state={
highlighted: false,
id: null
}
// The purpose of this function is to set the state to the target index on press
indexStateHandler = (i) =>{
if(this.state.id === null){
this.setState({
id: i
})
}else{
this.setState({
id:i
})
}
console.log("index: "+i)
console.log("state: "+this.state.id)
}
//The purpose of this function is to set styles for the targeted index
highlightStateHandler = (i) =>{
if(this.state.id === i){
if(!this.state.highlighted){
this.setState({
highlighted:true
})
}
else{
this.setState({
highlighted:false
})
}
}
}
highlightHandler = (i) =>{
// console.log(i)
this.indexStateHandler(i)
this.highlightStateHandler(i)
}
render() {
return (
<View style={styles.selectionWrapper}>
<View style={styles.label}><Text style={{color: "black"}}>{this.props.label}</Text></View>
<View style={styles.listContainer}>
{this.props.options.map((options, i) => (
<TouchableOpacity onPress={()=>this.highlightHandler(i)} key={i}>
<View style={this.state.highlighted&&this.state.id == i?styles.highlighted:styles.options} > <Text style={styles.text}>{options}</Text> </View>
</TouchableOpacity>
)
)}
</View>
</View>
);
}
}
const styles= StyleSheet.create({
selectionWrapper:{
width: '100%',
height: 100,
borderWidth: 1,
borderColor: 'red',
},
label:{
flex: 1,
}
,
listContainer:{
flex: 3,
flexDirection: "row",
justifyContent: "space-around",
alignItems: 'center',
// backgroundColor: "#7fffd4"
},
options:{
borderRadius: 10,
padding: 5,
borderWidth: 1,
borderColor: "#d0b783",
// backgroundColor: ""
},
text:{
color: 'black',
textAlign: 'center'
},
highlighted:{
borderRadius: 10,
padding: 5,
borderWidth: 1,
// borderColor: "#d0b783",
backgroundColor: "#d0b783"
}
})
export default Selections
.....
.....
.....
<TouchableOpacity
style={[styles.buttonStyle,{
backgroundColor : item.id === this.state.selectedItem.id ? "red" : "blue"
}]}
>
{
...
...
}
</TouchableOpacity>
.....
.....
.....
Have a look on TouchableOpacity and TouchableHighlight and try to run examples to see how they work. Also you can combine them to changing visual changes by changing styles.
import React, { Component } from 'react' import { AppRegistry, StyleSheet, TouchableOpacity, Text, View, } from 'react-native'
export default class App extends React.Component { constructor(props) {
super(props)
this.state = {
itemEn1: true,
itemEn2: false,
itemEn3: false,
} }
onPress1 = () => {
this.setState({
itemEn1: true,
itemEn2: false,
itemEn3: false,
}) }
onPress2 = () => {
this.setState({
itemEn1: false,
itemEn2: true,
itemEn3: false,
}) }
onPress3 = () => {
this.setState({
itemEn1: false,
itemEn2: false,
itemEn3: true,
}) }
render() {
return (
<View style={styles.container}>
<TouchableOpacity
style={this.state.itemEn1 ? styles.buttonEnabled : styles.buttonDisabled}
onPress={this.onPress1}>
<Text> Item 1 </Text>
</TouchableOpacity>
<TouchableOpacity
style={this.state.itemEn2 ? styles.buttonEnabled : styles.buttonDisabled}
onPress={this.onPress2}>
<Text> Item 2 </Text>
</TouchableOpacity>
<TouchableOpacity
style={this.state.itemEn3 ? styles.buttonEnabled : styles.buttonDisabled}
onPress={this.onPress3}>
<Text> Item 3 </Text>
</TouchableOpacity>
</View>
) } }
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 10
},
buttonDisabled: {
alignItems: 'center',
backgroundColor: '#DDDDDD',
padding: 10,
marginTop: 20
},
buttonEnabled: {
alignItems: 'center',
backgroundColor: 'green',
padding: 10,
marginTop: 20
},
countContainer: {
alignItems: 'center',
padding: 10
},
})
this is by map function:
export default class DataCollector extends React.Component {
constructor(props) {
super(props);
this.SendBack = this.SendBack.bind(this);
}
SendBack(info) {
console.log("Key is :", info);
this.props.callback(info);
}
render() {
let testData = this.props.data.map(function (articleData, index) {
return (
<View key={index}>
<TouchableOpacity
activeOpacity={0.6}
key={index}
onPress={() => this.callBack([articleData.id, articleData.name])}>
</TouchableOpacity>
</View>
)
}, this);
return (
<View>
{testData}
</View>
);
}
}
so now you have access to the clicked item and can use it for enable/disable etc..

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 how to pass this.setState change to parent

I am new to React Native I am making a sample app where the user can login and register for a new account.
I have two React classes,
One is the main class index.ios.js and another class called register.js. In the index class I am saying if the variable register is true render the register screen.
In the class register.js I am trying to set the variable register to false using this.setState({register:false}) but it is not causing the re render of the parent (index.ios.js). Is the a super(state) method or something similar that I am missing ? I believe the parent state is not getting the values of the updated register variable.
Here are my classes:
Render inside index.ios.js:
render: function() {
if(this.state.register) {
return this.renderRegisterScreen();
}
else if (this.state.loggedIn) {
return this.userLoggedIn();
}
else {
return this.renderLoginScreen();
}
}
Register.js:
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
Image,
TouchableHighlight,
TextInput,
} = React;
var Register = React.createClass({
render: function() {
return (
<View style={styles.container}>
<View style={styles.rafitoImage}>
<Image source={require('./logo.png')}></Image>
<Text style={styles.slogan}>Eliminate the need to wait!</Text>
</View>
<View style={styles.bottomSection}>
<View style={styles.username}>
<View style={styles.inputBorder}>
<TextInput placeholder="Username..." style={styles.usernameInput} onChangeText={(text) => this.setState({username: text})}/>
</View>
<View style={styles.inputBorder}>
<TextInput password={true} placeholder="Password..." style={styles.usernameInput} onChangeText={(text) => this.setState({password: text})}/>
</View>
<View style={styles.inputBorder}>
<TextInput password={true} placeholder="Verify Password..." style={styles.usernameInput} onChangeText={(text) => this.setState({verifyPassword: text})}/>
</View>
<View style={styles.inputBorder}>
<TextInput placeholder="Phone.." style={styles.usernameInput} onChangeText={(text) => this.setState({phone: text})}/>
</View>
<View style={styles.inputBorder}>
<TextInput placeholder="Email.." style={styles.usernameInput} onChangeText={(text) => this.setState({email: text})}/>
</View>
<TouchableHighlight style={styles.button}
underlayColor='#f1c40f' onPress={this.register}>
<Text style={styles.buttonText}>Register</Text>
</TouchableHighlight>
<TouchableHighlight style={styles.signUp} onPress={this.resetToLogin}
underlayColor='#ffffff'>
<Text style={styles.signUpText}>Already A Member </Text>
</TouchableHighlight>
</View>
</View>
<View style={styles.copyright}>
</View>
</View>
);
},
resetToLogin: function() {
this.setState({
register: false //I want this to re render the home screen with the variable register as false
});
}
});
var styles = StyleSheet.create({
container: {
flex : 1
},
bottomSection: {
flex: 5,
flexDirection: 'row'
},
button: {
height: 36,
backgroundColor: '#32c5d2',
justifyContent: 'center',
marginTop: 20
},
buttonText: {
fontSize: 18,
color: 'white',
alignSelf: 'center'
},
signUpText: {
color: '#3598dc'
},
signUp: {
alignItems: 'flex-end',
marginTop: 10,
},
username: {
flex: 1,
padding: 5
},
rafitoImage: {
flex: 3,
justifyContent: 'center',
alignItems: 'center',
},
copyright: {
alignItems: 'center'
},
usernameInput: {
height: 36,
marginTop: 10,
marginBottom: 10,
fontSize: 18,
padding: 5
},
copyrightText: {
color: '#cccccc',
fontSize: 12
},
inputBorder: {
borderBottomWidth: 1,
borderBottomColor: '#ececec'
},
slogan: {
color: '#3598dc'
}
});
module.exports = Register;
Attempt 1
As per the answer I added this to my index.ios.js
renderRegisterScreen: function() {
return (
<Register login={this.login}/>
)
}
And I added this to my register.js
<TouchableHighlight style={styles.signUp} onPress={this.props.login}
underlayColor='#ffffff'>
<Text style={styles.signUpText}>Already A Member </Text>
</TouchableHighlight>
But for some reason it does not even go to the register screen anymore, it executes the login function as soon as the register screen renders. What am I missing now ? Please advise.
Thanks
Update
It works when I pass down registered as a property but not when I do not. I would like to understand why if someone could post that.
Thanks
You can pass the function down to the child as props, then set the state of the parent from within the child that way.
Parent Component:
var Parent = React.createClass({
getInitialState() {
return {
registered: false
}
},
register(){
console.log("logging in... ");
this.setState({
registered: true
});
},
render: function() {
return (
<View style={styles.container}>
<Child register={this.register.bind(this)} registered={this.state.registered} />
{this.state.registered && <View style={{padding:10, backgroundColor:'white', marginTop:10}}>
<Text style={{fontSize:20}}>Congratulations, you are now registered!</Text>
</View>}
</View>
);
}
});
Child Component:
var Child = React.createClass({
render: function() {
return(
<View style={{backgroundColor: 'red', paddingBottom:20, paddingTop:20 }}>
<TouchableHighlight style={{padding:20, color: 'white', backgroundColor: 'black'}} onPress={() => this.props.register() }>
{this.props.registered ? <Text style={{color: 'white'}}>registered</Text> : <Text style={{color: 'white'}}>register</Text>}
</TouchableHighlight>
</View>
)
}
})
Here is a more powerful solution. This will let the child component change any state variable in the parent.
Parent component:
render: function() {
return (
...
<Child setParentState={newState=>this.setState(newState)} />
...
);
}
// Take note of the setState()
Child component:
this.props.setParentState({registered: true})
Why my attempt was failing was because I was using
onPress={this.props.login}
It should be
onPress={()=>this.props.login}
because of that mistake my onPress function would execute as soon as the button would render. I am not sure why that happens but I know what my mistake was.
Using StackNavigator I found a soultion leveraging screenProps. Here you can pass down functions and values to your routes. App global state is managed in App. App then passes in functions and/or state to NavComponent screenProps. Each child route in StackNavigator will then have access via this.props.screenProps
This solution is working well for now. Would love some feedback, or suggestions for improving this method
class HomeScreen extends React.Component {
render() {
return (
<View>
<Text>{JSON.stringify(this.props.screenProps.awesome)}</Text>
<Button
onPress={() => this.props.screenProps.updateGlobalState("data")}
title="Update parent State"
/>
</View>
);
}
}
const NavComponent = StackNavigator({
Home: { screen: HomeScreen },
// AllOthers: { screen: AllComponentsHereMayAccessScreenProps },
});
export default class App extends React.Component {
constructor() {
super();
this.state = {
everythingIsAwesome: false,
}
}
_updateGlobalState(payload) {
console.log('updating global state: ', payload);
this.setState({everythingIsAwesome: payload});
}
render() {
return <NavComponent screenProps={{
updateGlobalState: this._updateGlobalState.bind(this),
awesome: this.state.everythingIsAwesome
}} />;
}
}

Categories