Text strings must be rendered within a <Text> component - reactjs

Please what is wrong with this code.I have removed all white spaces. I have checked for semi colons in the code. I still have the same error.
I read before that it could happen because of white empty spaces but I don't see any empty white spaces in my code below. I have edited the question.
import React, { Component } from 'react';
import { StyleSheet, ScrollView, View } from 'react-native';
import { List, ListItem, Text, Card } from 'react-native-elements';
class DetailsScreen extends Component {
static navigationOptions = {
title: 'Details',
};
render() {
const { navigation } = this.props;
const matches = JSON.parse(navigation.getParam('matches', 'No matches found'));
console.log(matches)
return (
<ScrollView>
<Card style={styles.container}>
{
matches.map((item, key) => (
<View key={key} style={styles.subContainer}>
<View>
<Text style={styles.baseText}>{item.group}</Text>
</View>
<View>
<Text style={styles.baseText}>{item.team1.name}</Text>
<Text>{item.team2.name}</Text>
</View>
<View>
<Text style={styles.baseText}>{item.date}</Text>
</View>
<View>
<Text style={styles.baseText}>{item.score1}</Text>
<Text>{item.score2}</Text>
</View>
if(item.goals1.length > 0) {
item.goals1.map((item2, key2) => (
<View key={key2}><Text style={styles.baseText}>{item2.name} {item2.minute}</Text></View>
))
}
if(item.goals2.length > 0) {
item.goals2.map((item3, key3) => (
<View key={key3}><Text style={styles.baseText}>{item3.name} {item3.minute}</Text></View>
))
}</View>
))
}
</Card>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20
},
subContainer: {
flex: 1,
paddingBottom: 20,
borderBottomWidth: 2,
borderBottomColor: '#CCCCCC'
},
baseText:{
fontFamily:'Cochin',
fontSize:14,
fontWeight:'bold'}
})
export default DetailsScreen;

remove h2, h3, h3 from Text components since it has no props (not fatal, but useless) and you dont need () here either ({item2.minute}) which actually breaks the code
i suggest also checking out what props and methods Text component have here:
https://facebook.github.io/react-native/docs/text.html
hope this helps

Agree with wijuwiju's answer also do not nest other elements including <Text> inside a <Text> component. It will mostly create problems even if now on one platform you don't see any problems.

Related

Select items and transfer selected items to another page

Hello I am creating an app, and am having difficulties trying to create a way where the user selects multiple images, which will then be passed on to another screen. Could I please get some help on this?
Much will be appreciated.
So, the way my app works is that, the user selects multiple items, then there should be an add button or a save button, that will get the selected items and display them to another screen. The items have a value which are Images, not text. This is purely the reason why I asked the question here because most of the React-Native tutorials include values based on text, rather than Images.
The problem I am having, is trying to figure out a way for the user to select multiple items, and clicking a save button, which will in return transfer all of the "selected items" to another screen to be display there. Much like a viewer.
import React, { Component } from 'react';
import { Text, View, StyleSheet, AppRegistry, FlatList, Image, TouchableOpacity } from 'react-native';
import flatListData from '../database';
class FlatListItem extends Component {
static navigationOptions = ({ navigation }) => ({
title: 'FirstScreen!'
})
render() {
return (
<View style={{
flex: 1,
flexDirection:'column',
}}>
<View style={{
flex: 1,
flexDirection:'row',
}}>
<View style={{
flex: 1,
flexDirection:'column',
height: 100
}}>
<TouchableOpacity onPress={() => this.props.navigation.navigate('SecondScreen')} >
<Image source={{uri: this.props.item.imageUrl}}
style={{width: 100, height: 100, margin: 5}}></Image>
</TouchableOpacity>
</View>
</View>
<View style={{
height: 1,
backgroundColor:'white'
}}>
</View>
</View>
);
}
}
class FirstScreen extends Component {
static navigationOptions = ({ navigation }) => ({
title: 'First Screen'
})
render() {
return (
<View style={{flex: 1, marginTop: 22}}>
<FlatList
data={flatListData}
renderItem={({item, index})=>{
//console.log(`Item = ${JSON.stringify(item)}, index = ${index}`);
return (
<FlatListItem item={item} index={index}>
</FlatListItem>);
}}
>
</FlatList>
</View>
);
}
}
export default example;
const styles = StyleSheet.create({
flatListItem: {
color: 'white',
padding: 10,
fontSize: 16,
}
});
Since you did not provide any sample code, so I will try to suggest a way to handle via pseudocode
You can abstract out the list of images into a centralized helper class, then you render from this helper class for user to select.
Now when user have selected one of the image, you just need to capture the ID or any unique identifier, and pass it to second screen.
On this second screen, just using this ID/unique identifier that you've received and search it from the aforementioned centralized helper class and render it.
Looks like you have two things to figure out;
one is keeping track of what items a user has selected on your image selection screen
sending the data back between screens
Looks like you are most likely using react-navigation based on your example so the simplest solution would be to take advantage of React's state and use react-navigation's parameter passing between screens.
With react-navigation you can use the second argument in navigation.navigate to pass parameters/callbacks to the other screen. So you can navigate to a screen and pass a callback to it as such.
...
this.props.navigation.navigate(
'ItemSelectionScreen',
{ onSubmit: (items) => { /* Do something with items */ } }
)
...
And here is a basic example of a selection screen with some comments to explain how it works.
import React from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'grey',
alignItems: 'center',
justifyContent: 'center'
}
});
class ItemSelectionScreen extends React.Component {
constructor(props) {
super(props);
this.onSubmit = () => props.navigation.getParam('onSubmit'); // Keep the passed callback once we have navigated to this screen
this.state = {
selectedItems: [] // Our initial selectedItems (empty)
};
}
handleToggle = (item, isSelected) => {
const { selectedItems } = this.state;
this.setState({ selectedItems: isSelected ? selectedItems.filter(ent => ent !== item) : [...selectedItems, item] }); // Toggle if an item is selected
};
handleSubmitAndExit = () => {
const { onSubmit } = this;
const { selectedItems } = this.state;
onSubmit(selectedItems); // Pass your selectedItems back to the other screen
this.props.navigation.goBack(); // And exit the screen
};
handleExit = () => {
this.props.navigation.goBack(); // Exit the screen without calling onSubmit
};
renderItem = (item, index) => {
const { selectedItems } = this.state;
const isSelected = selectedItems.some(ent => ent === item); // Determine if an item is selected
return (
<TouchableOpacity key={index} onPress={() => this.handleToggle(item, isSelected)}>
<Text>{`${isSelected ? 'X' : 'O'} ${item}`}</Text>
</TouchableOpacity>
);
};
render() {
return (
<View style={styles.container}>
{['item1', 'item2', 'item3'].map(this.renderItem)}
<TouchableOpacity onPress={this.handleSubmitAndExit}>
<Text>Submit and Exit</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.handleExit}>
<Text>Exit</Text>
</TouchableOpacity>
</View>
);
}
}
export default ItemSelectionScreen;
Good luck and hope this was helpful.

React Navigation - pop() go's back to root rather than previous page

I am trying to add a back buttons into a bespoke sidemenu component.
Here is my navigation.js setup:
import { createAppContainer, createStackNavigator, createDrawerNavigator } from 'react-navigation';
import App from '../components/App';
import HomeView from '../components/HomeView';
import CheckIn from '../components/CheckIn';
import LoginView from '../components/LoginView';
import LrmDocs from '../components/LrmDocs';
import Rota from '../components/Rota';
import SideMenu from '../components/util/SideMenu';
const InitStack = createStackNavigator({
AppContainer: App,
LoginViewContainer:LoginView,
});
const RootStack = createDrawerNavigator({
Auth:InitStack,
HomeViewContainer: HomeView,
RotaContainer: Rota,
CheckInContainer:CheckIn,
LrmDocsContainer: LrmDocs,
},
{
drawerPosition: 'right',
contentComponent: SideMenu,
cardStyle: { backgroundColor: '#FFFFFF'},
drawerLockMode: 'locked-closed'
}
);
let Navigation = createAppContainer(RootStack);
export default Navigation;
I have the following setup in my bespoke sidemenu -
mport React, {Component} from 'react';
import CopyrightSpiel from './CopyrightSpiel';
import {ScrollView, Text, View, StyleSheet, Image, Button, TouchableOpacity} from 'react-native';
import { withNavigation } from 'react-navigation';
import { connect } from "react-redux";
import { authLogout, clearUser } from "../../store/actions/index";
class SideMenu extends Component {
constructor(props) {
super(props);
this.state = { loggedIn:false};
}
logOutHandler = () => {
this.props.onTryLogout();
this.props.clearUser();
this.props.navigation.navigate('AppContainer');
};
render() {
const isLoggedIn = () => {
if(this.state.loggedIn){
return true;
}
else {return false; }
};
let cp = this.props.activeItemKey;
let getCurrentCoordinates = (pg) => {
if(cp === pg){
return true;
}
};
return (
<View style={styles.container}>
<ScrollView>
<View style={styles.header}>
<View style={styles.closeBtnWrap}>
<TouchableOpacity
onPress={() => this.props.navigation.toggleDrawer() }
>
<Image
style={styles.closeBtnImg}
source={require('../../images/icons/ico-close.png')}
/>
</TouchableOpacity>
</View>
<View style={styles.logoBlock}>
<Image style={styles.homeBlockImg} source={require('../../images/loginLogo.png')} />
</View>
</View>
<View style={styles.navSection}>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('HomeViewContainer')}
>
<View style={[styles.navSectionStyle, getCurrentCoordinates('HomeViewContainer') && styles.navItemSel]}>
<Text style={styles.navItemStyle}>
HOME
</Text>
</View>
</TouchableOpacity>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('RotaContainer')}
>
<View style={[styles.navSectionStyle, getCurrentCoordinates('RotaContainer') && styles.navItemSel]}>
<Text style={styles.navItemStyle} >
MY ROTA
</Text>
</View>
</TouchableOpacity>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('LrmDocsContainer')}
>
<View style={[styles.navSectionStyle, getCurrentCoordinates('LrmDocsContainer') && styles.navItemSel]}>
<Text style={styles.navItemStyle} >
LRM DOCS
</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={this.logOutHandler}>
<View style={styles.navSectionStyle}>
<Text style={styles.navItemStyle} >
SIGN OUT
</Text>
</View>
</TouchableOpacity>
</View>
<View style={styles.navSection}>
<Text style={styles.navSectionTitle}>Current Shift Options:</Text>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('CheckInContainer')}
>
<View style={[styles.navSectionStyle, isLoggedIn() && styles.checkedInHide, getCurrentCoordinates('CheckInContainer') && styles.navItemSel]}>
<Text style={styles.navItemStyle} >
CHECK IN
</Text>
</View>
</TouchableOpacity>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('CheckInContainer')}
>
<View style={[styles.navSectionStyle, !(isLoggedIn()) && styles.checkedOutHide, getCurrentCoordinates('CheckInContainer') && styles.navItemSel]}>
<Text style={styles.navItemStyle} >
CHECK OUT
</Text>
</View>
</TouchableOpacity>
</View>
</ScrollView>
<View style={styles.footerContainer}>
<CopyrightSpiel color="LightGrey"/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
header:{
flexDirection:'row',
justifyContent:'center',
},
closeBtnWrap:{
position:'absolute',
left:15,
top:0,
opacity:0.8,
},
closeBtnImg:{
width:22,
height:22
},
container:{
backgroundColor:'#1C2344',
alignSelf:'stretch',
flex:1,
paddingTop:50,
borderLeftColor:'#F7931E',
borderLeftWidth:1
},
logoBlock:{
alignSelf:'center',
},
homeBlockImg:{
marginTop:10,
width:60,
height:105,
},
navSectionStyle:{
alignItems:'stretch',
textAlign: 'center',
backgroundColor:'rgba(255,255,255,0.1)',
paddingTop:8,
paddingBottom:8,
marginTop:15,
},
navItemSel:{
backgroundColor:'rgba(255,255,255,0.9)',
},
navItemSelText:{
color:'#1C2344',
},
navItemStyle:{
color:'#F7931E',
fontSize:24,
alignSelf:'center'
},
navSection:{
marginTop:30
},
navSectionTitle:{
color:'rgba(255,255,255,0.5)',
marginLeft:15,
},
footerContainer:{
paddingBottom:15,
},
checkedInHide:{
display:'none',
},
checkedOutHide:{
display:'none',
},
});
const mapDispatchToProps = dispatch => {
return {
onTryLogout: () => dispatch(authLogout()),
clearUser: () => dispatch(clearUser())
};
};
export default connect(null, mapDispatchToProps)(withNavigation(SideMenu));
which works fine -
I then have the following in my sub view header:
import React from 'react';
import {View, Image, Text, StyleSheet, TouchableOpacity, Button} from 'react-native';
import PropTypes from 'prop-types';
import { withNavigation } from 'react-navigation';
import { StackActions } from 'react-navigation';
class FixedHeader extends React.Component {
render() {
const popAction = StackActions.pop({
n: 0,
});
return (
<View style={FixedHeaderStyles.sectionHeader}>
<View style={FixedHeaderStyles.sectionHeaderTopLine}>
<View style={[FixedHeaderStyles.sectionHeaderBack, !(this.props.backButton) && FixedHeaderStyles.sectionHeaderHide ]}>
<TouchableOpacity
onPress={() => this.props.navigation.dispatch(popAction)}
>
<Text style={FixedHeaderStyles.sectionHeaderText}>< Back</Text>
</TouchableOpacity>
</View>
<View style={FixedHeaderStyles.logoBlock}>
<Image style={FixedHeaderStyles.homeBlockImg} source={require('../../images/logosmall.png')} />
</View>
<View style={FixedHeaderStyles.homeBlockBurger} >
<TouchableOpacity onPress={() => this.props.navigation.toggleDrawer() }>
<Image
style={FixedHeaderStyles.homeBurgerImg}
source={require('../../images/icons/ico-burger.png')}
/>
</ TouchableOpacity>
</View>
</View>
</View>
);
}
}
FixedHeader.propTypes = {
backButton: PropTypes.bool.isRequired,
navigate: PropTypes.object,
};
const FixedHeaderStyles = StyleSheet.create({
sectionHeadeLogo:{
width:45,
height:58,
alignSelf:'center'
},
sectionHeader:{
backgroundColor:'#1C2344',
flex:1.8,
alignSelf:'stretch',
borderBottomColor:'#f79431',
borderBottomWidth:1,
},
sectionHeaderTopLine:{
height:120,
paddingTop:45,
borderBottomColor:'#f79431',
borderBottomWidth:1,
flexDirection:'row',
justifyContent:'center',
alignItems:'center'
},
homeBlockBurger:{
position:'absolute',
right:0,
marginRight:15,
top:56
},
logoBlock:{
alignSelf:'flex-start',
},
homeBlockImg:{
width:45,
height:58,
alignSelf:'center',
},
homeBurgerImg:{
width:40,
height:40,
},
sectionHeaderHide:{
display:'none',
},
sectionHeaderBack:{
position:'absolute',
left:15,
top:70,
},
sectionHeaderText:{
color:'#fff',
},
});
export default withNavigation(FixedHeader);
The page navigates fine to the subview - but when pressing back the page jumps to the root (login page) rather than the previous page. For example - I navigate to rota from home, click back and jump back to login.. can anyone shine any light on this and point me in the correct direction - I've read the documentation but cant figure out whats going astray...
My Dependencies are as follows:
Here's how to do it in #react-navigation 6.x -we're in 2022 xD-
import { StackActions } from '#react-navigation/native';
const popAction = StackActions.pop(1);
navigation.dispatch(popAction);
documentation demo
https://reactnavigation.org/docs/stack-actions/#pop
snack demo https://snack.expo.dev/JEqNk9eBx
You shouldn't define your popAction with index to 0 in your FixedHeader class.
const popAction = StackActions.pop({
n: 0,
});
instead try
const popAction = StackActions.pop();
The pop action takes you back to a previous screen in the stack.
The n param allows you to specify how many screens to pop back
by.
Please refer to these docs: https://reactnavigation.org/docs/en/stack-actions.html#pop
Besides that, you would better define your const popAction = ... outside render() method.
import React from 'react';
import {View, Image, Text, StyleSheet, TouchableOpacity, Button} from 'react-native';
import PropTypes from 'prop-types';
import { withNavigation } from 'react-navigation';
import { StackActions } from 'react-navigation';
const popAction = StackActions.pop();
class FixedHeader extends React.Component {
render() {
return (
<View style={FixedHeaderStyles.sectionHeader}>
<View style={FixedHeaderStyles.sectionHeaderTopLine}>
<View style={[FixedHeaderStyles.sectionHeaderBack, !(this.props.backButton) && FixedHeaderStyles.sectionHeaderHide ]}>
<TouchableOpacity
onPress={() => this.props.navigation.dispatch(popAction)}
>
<Text style={FixedHeaderStyles.sectionHeaderText}>< Back</Text>
</TouchableOpacity>
</View>
<View style={FixedHeaderStyles.logoBlock}>
<Image style={FixedHeaderStyles.homeBlockImg} source={require('../../images/logosmall.png')} />
</View>
<View style={FixedHeaderStyles.homeBlockBurger} >
<TouchableOpacity onPress={() => this.props.navigation.toggleDrawer() }>
<Image
style={FixedHeaderStyles.homeBurgerImg}
source={require('../../images/icons/ico-burger.png')}
/>
</ TouchableOpacity>
</View>
</View>
</View>
);
}
}
FixedHeader.propTypes = {
backButton: PropTypes.bool.isRequired,
navigate: PropTypes.object,
};
const FixedHeaderStyles = StyleSheet.create({
sectionHeadeLogo:{
width:45,
height:58,
alignSelf:'center'
},
sectionHeader:{
backgroundColor:'#1C2344',
flex:1.8,
alignSelf:'stretch',
borderBottomColor:'#f79431',
borderBottomWidth:1,
},
sectionHeaderTopLine:{
height:120,
paddingTop:45,
borderBottomColor:'#f79431',
borderBottomWidth:1,
flexDirection:'row',
justifyContent:'center',
alignItems:'center'
},
homeBlockBurger:{
position:'absolute',
right:0,
marginRight:15,
top:56
},
logoBlock:{
alignSelf:'flex-start',
},
homeBlockImg:{
width:45,
height:58,
alignSelf:'center',
},
homeBurgerImg:{
width:40,
height:40,
},
sectionHeaderHide:{
display:'none',
},
sectionHeaderBack:{
position:'absolute',
left:15,
top:70,
},
sectionHeaderText:{
color:'#fff',
},
});
export default withNavigation(FixedHeader);
Cheers
Since you're using the withNavigation HOC, you'll want to use the navigation prop in your FixedHeader component instead of calling StackActions.pop. you can just call this.props.navigation.pop().
https://reactnavigation.org/docs/en/navigation-prop.html#navigator-dependent-functions
After a fair bit of head scratching and searching - I found an answer to my issue - My problem is that i'm using a drawer navigation rather than stack navigation - pop is not available to a drawer as there isnt an avilable stack -
ref - https://reactnavigation.org/docs/en/navigation-prop.html
answer from - https://github.com/react-navigation/react-navigation/issues/4793
The pop action takes you back to a previous screen in the stack. It takes one optional argument (count), which allows you to specify how many screens to pop back by.
import { StackActions } from '#react-navigation/native';
const popAction = StackActions.pop(1);
navigation.dispatch(popAction);

React Native TouchableOpacity OnPress not Working with loop

I have a scrollview in which multiple items are generated with loop. I added TouchableOpacity above these items because i want these objects to be touchable. But when i add a method on onPress method it shows error not a function , is undefined
List_Data Component:
class List_Data extends React.Component {
fetchData = () => {
console.log("DONE");
}
_renderView = () => {
return (
<View style={{flex:1, padding: 20}}>
<View style={styles.container}>
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false} >
{
this.state.Data.map(function (data, index) {
return (
<TouchableOpacity key={index} onPress={() => this.fetchData()}>
<Image source={{uri: data.imageSrc}}
resizeMode={'cover'}
style={{width: '100%', height: imageHeight}}
/>
</TouchableOpacity>
);
})
}
</ScrollView>
</View>
</View>
)
}
render() {
return (
{this._renderView()}
);
}
}
I don't know whats the issue, it just a method which prints on console.
The issue is coming from your .map. Basically you are losing the value of this as you are not using an arrow function. If you change your .map(function(data, index) to .map((data,index) => it should work.
import * as React from 'react';
import { Text, View, StyleSheet, ScrollView, TouchableOpacity, Image } from 'react-native';
import { Constants } from 'expo';
export default class App extends React.Component {
state = {
Data: [
{imageSrc :'https://randomuser.me/api/portraits/men/39.jpg'},
{imageSrc: 'https://randomuser.me/api/portraits/women/38.jpg'},
{imageSrc: 'https://randomuser.me/api/portraits/men/37.jpg'},
{imageSrc: 'https://randomuser.me/api/portraits/women/36.jpg'},
{imageSrc: 'https://randomuser.me/api/portraits/men/35.jpg'},
{imageSrc: 'https://randomuser.me/api/portraits/women/34.jpg'},
]
}
// let's pass something so that we know that it is working
fetchData = (index) => {
alert(`you pressed ${index}`)
}
_renderView = () => {
return (
<View style={{flex: 1, padding: 20}}>
<View style={styles.container}>
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false} >
{
this.state.Data.map((data, index) => { // change this to an arrow function
return (
<TouchableOpacity key={index} onPress={() => this.fetchData(index)}>
<Image source={{uri: data.imageSrc}}
resizeMode={'cover'}
style={{width: 100, height: 100}}
/>
</TouchableOpacity>
);
})
}
</ScrollView>
</View>
</View>
);
}
render() {
return (
this._renderView()
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
}
});
You can see it working in the following snack https://snack.expo.io/#andypandy/map-with-arrow-function
Try keyboardShouldPersistTaps={true} under ScrollView. <ScrollView keyboardShouldPersistTaps={true}>

Add data in React Native and Save the State

I'm building a basic React Native application where the user enters his name in a TextInput and on button press his name along with his image is added to a ScrollView in another View. Images are stored and named in accord with the name of the person. Example - Name: 'ABC', the image fetched from assets will be 'ABC.jpg'.
I'm able to do this for one person, but every time I add a new entry the previous one gets overwritten. How can I retain the previous entry yet add another entry?
Home
import React, {Component} from 'react';
import { StyleSheet, Text, View, Image, ScrollView, Button, TouchableWithoutFeedback, TextInput} from 'react-native';
import { createStackNavigator } from 'react-navigation';
class HomeScreen extends React.Component {
render() {
const { navigation } = this.props;
const name0 = navigation.getParam('name0', 'NO-ID');
return (
<View style={styles.container}>
<ScrollView vertical={true} contentContainerStyle={{flexGrow: 1}}>
<Text style={styles.category}>Category 1</Text>
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false}>
<TouchableWithoutFeedback onPress={() => {
this.props.navigation.navigate('Details', {
name: name0,
intro: 'lorem ipsum',
detail1: 'XYZ',
detail2: 'ABC',
});
}}>
<View style={styles.view}>
<Image source={require('./assets/rohit.jpg')} style={styles.image}></Image>
<Text style={styles.text}>{name0}</Text>
</View>
</TouchableWithoutFeedback>
</ScrollView>
</ScrollView>
</View>
)
}
}
Add Data
class AddData extends React.Component {
constructor(props) {
super(props);
this.state = { text: '' };
}
render() {
function onPressLearnMore() {
alert('Hi')
}
return (
<View style={{flex: 1, flexDirection: 'column', justifyContent:'center', alignItems: 'center'}}>
<TextInput
style={{height: 40,width:200}}
onChangeText={(text) => this.setState({input: text})}
/>
<Button
onPress={() => {
this.props.navigation.navigate('Home', {
name0: this.state.input
});
}}
title="Pass Data"
/>
</View>
);
}
}
Navigator
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
Data: AddData
},
{
initialRouteName: 'Data',
}
);
export default class App extends React.Component {
render() {
return <RootStack />;
}
}
Screen 1
Screen 2
Because you aren't saving your data from the user input anywhere, simply passing it back to home, it is getting overwritten and as your code sits, it is working! ;)
To simply put a bandaid on what you're doing, because this method of passing data is slightly taboo.. and you cannot achieve what you're asking without some sort of state persistence like AsyncStorage, or... to not have two screens. Because everytime React re-renders your screen any data that was in your state object disappears...
Inside your home component, on did mount you could store user input to state as objects inside an array. IN the below example I am using the user data you are sending back to home, however this would need to be data retrieved from some sort of persistence.
class HomeScreen extends React.Component {
constructor(props) {
super(props)
this.state = {
usersArray: []
}
}
componentDidMount() {
let userInfo = this.props.navigation.getParam('name0', 'NO-ID');
userInfo !== undefined ? this.setState({usersArray:
[...this.state.usersArray, userInfo]}) : console.log('NO USER DATA to add')
}
render() {
const { navigation } = this.props;
const name0 = navigation.getParam('name0', 'NO-ID');
return (
<View style={styles.container}>
<ScrollView vertical={true} contentContainerStyle={{flexGrow: 1}}>
<Text style={styles.category}>Category 1</Text>
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false}>
<TouchableWithoutFeedback onPress={() => {
this.props.navigation.navigate('Details', {
name: name0,
intro: 'lorem ipsum',
detail1: 'XYZ',
detail2: 'ABC',
});
}}>
<View style={styles.view}>
<Image source={require('./assets/rohit.jpg')} style={styles.image}></Image>
{/* <Text style={styles.text}>{name0}</Text> */}
{ this.state.usersArray.map((ele, index) => {
return <Text key={index} style={styles.text}>{ele.name}</Text>
})}
</View>
</TouchableWithoutFeedback>
</ScrollView>
</ScrollView>
</View>
)
}
}
Please keep in mind you may need to change your user data to be objects for this rest and spreading to work.

Change active state and flex transition

I have a react component class like below
<View style={{flex: 1}}>
<TouchableOpacity style={styles.FreeCoffee}/>
<TouchableOpacity style={styles.Help}/>
</View>
both touchableopacity components have the value of flex 2 so they equally divided in window. When one of the touchableopacity pressed, I want to make a transition between flex to 2 into 4 so that one box can grow with animation, also mark it as a "active" or "selected" one. I have searched this many many times but since I am a beginner in ReactNative, I couldn't find any proper way to that.
Is this possible or achiveable ?
//Edit Full Code
import React from 'react'
import {ScrollView, Text, View, TouchableOpacity, Button} from 'react-native'
import styles from '../Styles/Containers/HomePageStyle'
export default class HomePage extends React.Component {
constructor(props){
super(props);
/*this.state = {
active : { flex : 8 }
}*/
}
render() {
return (
<View style={styles.mainContainer}>
<View style={{flex: 1}}>
<TouchableOpacity style={styles.FreeCoffee}/>
<TouchableOpacity style={styles.Help}/>
</View>
</View>
)
}
componentWillMount(){
}
animateThis(e) {
}
}
You can use LayoutAnimation to do this. Define state that toggles the styles that are applied to your render and use onPress in the TouchableOpacity to define your function that Calls the LayoutAnimation and setState. Something like the following:
import React from 'react';
import { LayoutAnimation, ScrollView, StyleSheet, Text, View, TouchableOpacity, Button } from 'react-native';
// import styles from '../Styles/Containers/HomePageStyle'
const styles = StyleSheet.create({
mainContainer: {
flexGrow: 1,
},
FreeCoffee: {
backgroundColor: 'brown',
flex: 2,
},
Help: {
backgroundColor: 'blue',
flex: 2,
},
active: {
flex: 4,
borderWidth: 1,
borderColor: 'yellow',
},
});
export default class HomeContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
active: 'neither',
};
this.setActive = this.setActive.bind(this);
}
setActive(active) {
// tells layout animation how to handle next onLayout change...
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
// set active in state so it triggers render() to re-render, so LayoutAnimation can do its thing
this.setState({
active,
});
}
render() {
return (
<View style={styles.mainContainer}>
<View style={{ flex: 1, backgroundColor: 'pink' }}>
<TouchableOpacity
style={[
styles.FreeCoffee,
(this.state.active === 'FreeCoffee') && styles.active]}
onPress={() => {
this.setActive('FreeCoffee');
}}
/>
<TouchableOpacity
style={[
styles.Help,
(this.state.active === 'Help') && styles.active]}
onPress={() => {
this.setActive('Help');
}}
/>
</View>
</View>
);
}
}

Resources