Updating State not updating view - javascript

I am currently learning React Native.
I have built a view which should show a text Loading when the data is being fetched and should display the data once the data has been received by the app.
The app is hitting the backend server and is getting the URL(tried console.error on app and it does popup with ared screen showing the correct data details ).
The problem is the view is not being updated. Another thing that is weird is that the conditional view is showing the border which has been set for the container, but it does not display any text or data except that. Even if I put the correct data. Not sure if the condition is being validated correctly or not.
The border I mentioned is set in articleContainer in the stylesheet and is attached with the container which is with the condition this.state.hasResult
If i remove the style from that view the border dissappears obviously but even putting a static text inside the view is not being displayed(checked incase I parsed the json wrong.) Seems a bit confusing.
var constants = require("../constants")
var React = require('react');
var ReactNative = require('react-native');
var t = require('tcomb-form-native');
var authenticate = require("../services/authenticate")
var {
AppRegistry,
AsyncStorage,
StyleSheet,
Text,
View,
TouchableHighlight,
Alert,
ListView,
Image,
} = ReactNative;
const options = {}
class RecipePage extends React.Component{
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1.id !== r2.id});
var getData = require("../services/get_featured");
var par = this;
var recipeId = props.recipeId;
this.state ={
hasResult: false,
noResult: false,
result: null,
isLoading: true,
}
getData(recipeId).then(function(data){
par.setState(
{
result:data,
hasResult:true,
noResult:false,
isLoading:false
}
)
}).catch(function(error) {
console.error(error);
});
}
goBack(){
this.props.navigator.pop();
}
render() {
return (
<View style={styles.container}>
<View style={styles.row}>
<Text style={styles.title}>Recipe</Text>
<TouchableHighlight onPress={this.goBack.bind(this)}>
<Image style={styles.back}
source={require("../static/images/back.png")}
/>
</TouchableHighlight>
</View>
{
this.state.hasResult &&
<View style={styles.article_container} >
<Text style={styles.article_title} >{this.state.result.id}</Text>
<Image style={styles.article_img}
source={{uri: this.state.result.image_link}}
/>
</View>
}
{
this.state.isLoading &&
<View style={styles.article_container} >
<Text style={styles.article_title} >Loading</Text>
</View>
}
</View>
);
}
}
var styles = StyleSheet.create({
container: {
justifyContent: 'center',
marginTop: 25,
padding: 20,
backgroundColor: '#ffffff',
},
title: {
fontSize: 30,
alignSelf: 'center',
marginBottom: 30
},
article_container: {
justifyContent: 'center',
marginTop: 5,
padding: 20,
backgroundColor: '#ffffff',
borderBottomColor: '#555555',
borderBottomWidth: 1,
flex:1
},
article_title: {
fontSize: 25,
alignSelf: 'center',
marginBottom: 3,
flex:2
},
article_img: {
width:200,
height:200,
alignSelf: 'center',
flex:1
},
article_description :{
fontSize:15,
flex:3
},
back:{
backgroundColor:'#ffffff',
width:20,
height:20
}
});
module.exports = RecipePage;
If you think I can improve the code not relating to this question, then feel free to comment and enlighten me :)
Edit:
I played around a bit more and found that if I change the attached styles as:-
<View style={styles.row} >
<Text style={styles.title} >{this.state.result.title}</Text>
<Image
source={{uri: this.state.result.image_link}}
/>
</View>
from
<View style={styles.article_container} >
<Text style={styles.article_title} >{this.state.result.id}</Text>
<Image style={styles.article_img}
source={{uri: this.state.result.image_link}}
/>
</View>
I am able to view the title after making this change, but image is still not displayed. And I am not sure why it was not showing for the other style.
Even if one of the style is attached -> article_title or article_container, its not being displayed.
Edit 2:
Even if I apply the style manually, it is not displayed like
<Text style={{fontSize: 25,alignSelf: 'center',marginBottom: 3,flex:2}} >{this.state.result.title}</Text>
I am navigating to this page from a parent which uses similar styles for a listview and it is showing there perfectly.

The problem seemed to be that I used flex property in styles without using ScrollView or ListView.
I would research more into that and update the answer.

Related

REACT NATIVE: Scroll View keep bouncing back up to the top doesn't scroll

I am trying to get my ScrollView to scroll down so I can see all my views but it keeps bouncing back up to the top.
What it looks like
The White panels below Physiological Classification are in the ScrollView and are supposed to scroll but it just bounces back to the top.
Here is where my ScrollView is
_renderContent = (section) => {
section.arrow = !(section.arrow);
return (
<ScrollView>
<QuestionPanels
Questions={section.Questions}
pickerDefaultValues={section.pickerDefaultValues}
pickerItemNames={section.pickerItemNames}
/>
</ScrollView>
);
};
Question Panels is just a component that generates Views based on a json file. If relevant here is the code for that as well.
import React, { Component, useState, setState} from 'react';
import { ScrollView, View, Text } from 'react-native'
import styles from '../../Styles/GeneralStyles';
import Picker from '../Picker/Picker'
import appData from '../../DataSheet/appData.json';
const Panel = (props) => {
return (
<View style={styles.dropDownCardPanel}>
<View style={styles.QuestionPanel}>
<Text style={styles.QuestionText}>{props.Question}</Text>
</View>
<View style={styles.AnswerPanel}>
<Picker
defaultVal= {props.pickerDefaultValues}
showButton={false}
pickerItemNames={props.pickerItemNames}
/>
</View>
</View>
);
}
export default class QuestionairePanels extends Component {
constructor(props){
super(props)
}
render() {
var panelList = [];
for(let i = 0; i < this.props.Questions.length; i++){
panelList.push(
<Panel
key={i}
Question={this.props.Questions[i]}
pickerDefaultValues ={this.props.pickerDefaultValues[i]}
pickerItemNames = {this.props.pickerItemNames[i]}
/>
);
}
return(
<View>
{panelList}
</View>
);
}
}
Here are the styles that matter for this
dropDownCardPanel: {
height: 200,
flexDirection: "row",
backgroundColor: '#faf2f2',
paddingTop: 5,
paddingBottom: 5,
borderBottomWidth: 1,
borderColor: 'black',
},
dropDownCardPanelText: {
fontSize: 15,
color: "black",
marginLeft: 10
},
icon: {
left: 20,
},
QuestionPanel: {
height: "100%",
width: "60%",
borderRightWidth: 1,
borderColor: 'black',
left: 3,
marginRight: 5,
alignItems: "center",
justifyContent:'center'
},
QuestionText: {
fontSize: 20,
},
AnswerPanel: {
height: "100%",
width: "40%",
right: 3
}
The reason why I was not able to scroll was that the tag needs a specific height for it to render for a scroll. So to fix this I had to put a view around the and set it to a specific height.
Corrected Code
section.arrow = !(section.arrow);
var scrollHeight = (section.Questions.length > 2) ? 600 : 400;
var headerDisplay = (section.name.match("Physiologic")) ? section.name + " Variables" : "Select Dominant Final Diagnosis";
return (
<View style={{height: scrollHeight}}>
<ScrollView>
<View style={styles.dropDownCardPanelHeader}>
<Text style={styles.dropDownCardPanelHeaderText}>
{headerDisplay}
</Text>
</View>
<QuestionPanels
Questions={section.Questions}
pickerItemNames={section.pickerItemNames}
/>
</ScrollView>
</View>
Later I will try to use Flex to set the height so the react native project can scale to all screens but so far it works for iOS

Text position in React Native

In react native I want to display some texts at some custom positions like in the following image:
custom location react native
How can I achieve this?
I've been playing with the following example:
import React, { Component } from 'react';
import { Text, StyleSheet } from 'react-native';
export default class TextInANest extends Component {
constructor(props) {
super(props);
this.state = {
titleText: "Bird's Nest",
bodyText: 'This is not really a bird nest.'
};
}
render() {
return (
<Text style={styles.baseText}>
<Text style={styles.titleText} onPress={this.onPressTitle}>
{this.state.titleText}{'\n'}{'\n'}
</Text>
<Text numberOfLines={5}>
{this.state.bodyText}
</Text>
</Text>
);
}
}
const styles = StyleSheet.create({
baseText: {
fontFamily: 'Cochin',
},
titleText: {
fontSize: 20,
fontWeight: 'bold',
},
});
trying to set titleText position to absolute and adding some top and leftvalues but it doesn't seem to work.
Any ideas?
From your screenshot, we could say that :
Go to Jane's profile takes 1/11 of the screen height, and is vertically centered
Bird's Nest takes 5/11 of the screen height
This is not... takes 5/11 of the screen height
As in React Native, the main axis is the vertical one (items are positionned below each others by default), you should use justifyContent to vertically centered a Text in a View.
So something like the follow should do the trick.
<View style={{ flex: 1 }}>
<Text>Go to Jane's profile</Text>
</View>
<View style={{ flex: 5, justifyContent: "center" }}>
<Text>Bird's Nest</Text>
</View>
<View style={{ flex: 5 }}>
<Text>This is not...</Text>
</View>
Improved code with working live demo https://snack.expo.io/#akhtarvahid/demo
export default class TextInANest extends React.Component {
constructor(props) {
super(props);
this.state = {
titleText: "Bird's Nest",
bodyText: 'This is not really a bird nest.'
};
}
render() {
return (
<Text style={styles.baseText}>
<Text style={styles.titleText} onPress={this.onPressTitle}>
{this.state.titleText}{'\n'}{'\n'}
</Text>
<Text numberOfLines={5} style={styles.bodyText}>
{this.state.bodyText}
</Text>
</Text>
);
}
}
const styles = StyleSheet.create({
baseText: {
fontFamily: 'Cochin',
},
titleText: {
fontSize: 20,
fontWeight: 'bold'
},
bodyText:{
position:'absolute',
left:10,
top:'50%'
}
});

React Native FlatList with clickable items

I'm building a custom line style for a react-native FlatList.
I want the user to navigate to item details when clicking on the line text, or navigate to another page (drill down next level) when clicked on the right caret, something like:
Here is my current list components code:
class MyList extends Component {
handleShowDetails = index => {
...
};
handleDrillDown = index => {
...
}
render = () => {
let data = // Whatever data here
return (
<View style={styles.container}>
<FlatList
data={data}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<MyListItem
onTextPress={this.handleShowDetails}
onCaretPress={this.handleDrillDown}
item={item}
/>
)}
/>
</View>
);
};
}
export default MyList;
const styles = StyleSheet.create({
container: {
flex: 1
},
item: {
padding: 10,
fontSize: 18,
height: 44,
backgroundColor: colors.white,
borderStyle: "solid",
marginBottom: 1
}
});
And my list item component:
class MyListItem extends Component {
handleTextPress = () => {
if (this.props.onTextPress) this.props.onTextPress(this.props.item.id);
};
handleIconPress =() => {
if (this.props.onCaretPress) this.props.onCaretPress(this.props.item.id)
}
render = () => {
return (
<View style={styles.container}>
<View style={styles.textContainer}>
<Text onPress={this.handleTextPress}>{this.props.item.title}</Text>
</View>
<View style={styles.iconContainer}>
<Button onPress={this.handleIconPress}>
<Icon name="ios-arrow-forward"/>
</Button>
</View>
</View>
);
};
}
export default MyListItem;
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
backgroundColor: colors.white,
marginBottom: 1,
height: 30
},
textContainer: {
backgroundColor: colors.light,
paddingLeft: 5,
fontSize: 26
},
iconContainer: {
alignSelf: "flex-end",
backgroundColor: colors.primary,
paddingRight: 5,
fontSize: 26
}
});
Problems I'm facing:
a. Clicking on text is not working properly. Sometimes it navigates but most of time I cannot navigate, specially if I click on the empty space between the text and the caret.
b. I simply cannot style the fontSize of the text.
c. I'm not being able to space then accordingly.
d. I need to vertical center both itens on row.
Here is what I'm getting for now:
For the clicking issue, you could set an TouchableHighlight or a TouchableOpacity for the View.
For spacing and alignment issues, maybe you could set the text to flex: 9 and the icon to flex: 1 with FlexBox. Here are the docs for that https://facebook.github.io/react-native/docs/flexbox.html.
a. Try to make the text full the cell. I can see your text just in 50% of the cell. style <Text> with height: 44
b. fontsize has to be placed in the <Text> component. You are placing it in <View> component
c. "I'm not being able to space then accordingly". I can't get your point clearly.
d. Try justifyContent: 'center' in iconContainer
For part a I would suggest an improvement over Anthu's answer:
I you want the entire textContainer to be clickable I suggest using TouchableWithoutFeedback (or another Touchable which suits your needs) and wrap this around the textContainer View

How to change button color when pressed in React Native using TouchableHighlight?

I am currently developing an application, and I am having trouble figuring out how to get the button to change color after being pressed using TouchableHighlight. Not to be confused with the underlayColor prop which I know exists as part of TouchableHighlight which only changes the color for when the button is pressed and then returns to its regular color.
This is what I have so far (Some of the code has been omitted for simplicity):
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
TouchableHighlight,
Alert,
} from 'react-native';
class MeetingScreen extends Component {
constructor(props){
super(props);
this.state = {
buttonColor: '#7395AE',
}
this.onButtonPress=this.onButtonPress.bind(this);
}
onButtonPress(){
this.setState({ buttonColor: 'red' });
}
render() {
return (
<View style={styles.container}>
<TouchableHighlight
style={styles.talk}
color={this.state.buttonColor}
onPress={() => this.state.buttonColor}
selected={this.onButtonPress}
>
<View>
<Text style={styles.welcome} >
Talk
</Text>
</View>
</TouchableHighlight>
</View>
);
}
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#7395AE',
},
welcome: {
fontSize: 30,
textAlign: 'center',
margin: 10,
color: '#ffffff',
},
talk:{
height: 200,
width: 200,
borderWidth: 5,
backgroundColor: '#7395AE',
borderRadius: 100,
borderColor: '#557A95',
justifyContent:'center',
alignItems:'center',
borderRadius: 100
},
});
export default connect(mapStoreToProps, mapDispatchToProps)(MeetingScreen);
I have looked at other answers on StackOverflow and have attempted a good portion of them but I couldn't find anything that fit specifically to my issue. I have also looked at the React Native documentation and wasn't able to find anything helpful. The code as it is right now just displays the button and when pressed it goes black but then goes back to it's original color after being pressed. What I am looking for is for the button to turn red and stay red after being pressed. Any help would be greatly appreciated. Thank you so much for any help in advance!
<TouchableHighlight
style={[styles.talk, { backgroundColor: this.state.buttonColor}]} //Or if don't want "backgroundColor:" and just need change the text color use => "color:""
onPress={() => this.state.buttonColor}
selected={this.onButtonPress}/>

TabBarIOS: onlyChild must be passed a children with exactly one child

I am new to react-native and I have an error trying to create TabBarIOS.
It keeps telling me onlyChild must be passed a children with exactly one child but my code is exactly identical with the tutorial I followed.
index.ios.js
'use strict';
var React = require('react-native');
var Welcome = require('./welcome.js');
var More = require('./more.js');
var {
Alert,
AppRegistry,
StyleSheet,
Text,
View,
Component,
TabBarIOS
} = React;
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#f5fcff',
alignItems: 'center'
},
button: {
height: 44,
flexDirection: 'row',
backgroundColor: '#488bec',
alignSelf: 'stretch',
justifyContent: 'center',
},
buttonText: {
fontSize: 18,
fontFamily: 'Helvetica',
color: 'white',
alignSelf: 'center',
}
});
class iCareReactNative extends Component {
constructor(props) {
super(props);
this.state = {
selectedTab: 'welcome'
};
}
render() {
return (
<TabBarIOS selectedTab={this.state.selectedTab}>
<TabBarIOS.Item
selected={this.state.selectedTab === 'welcome'}
systemIcon="featured"
onPress={() => {
this.setState({
selectedTab: 'welcome'
});
}}>
<Welcome/>//welcome component
</TabBarIOS.Item>
<TabBarIOS.Item
selected={this.state.selectedTab === 'more'}
systemIcon="contacts"
onPress={() => {
this.setState({
selectedTab: 'more'
});
}}>
<More/>//more component
</TabBarIOS.Item>
</TabBarIOS>
)
}
}
AppRegistry.registerComponent('iCareReactNative', () => iCareReactNative);
welcome.js
'use strict';
var React = require('react-native');
var {
StyleSheet,
View,
Text,
Component
} = React;
var styles = StyleSheet.create({
description: {
fontSize: 20,
textAlign: 'center',
color: '#FFFFFF'
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#123456'
}
});
class Welcome extends Component {
render() {
return(
<View style={styles.container}>
<Text style={styles.description}>
Welcome to Welcome
</Text>
</View>
);
}
}
module.exports = Welcome;
I found that usually this error will be triggered by TouchableHighlight LINK but I didn't use any of those.
Any idea?
This error is triggered when a component expects a single valid React element as a child and doesn't get one. To debug this issue, you will generally look for a component that hasn't been properly imported, or whose render method returns null.
In your case, the component expecting a child and not getting one is the selected TabBarIOS.Item. If you set both selected props of your TabBarIOS.Item components to false, you'll see that the error disappears.
Now why doesn't it find the Welcome and More components ? Because of the comment in your render method (//welcome component, //more component). Remove the comments and the error will be solved.
I'm not sure, though, why the comments didn't trigger an exception : it should complain that some text isn't wrapped in a Text component. Maybe something to do with your react-native version.

Categories