As I am working on react native platform, I have achieved many UI and dynamic challenges but here I have multiple view which I am creating dynamically as per the API response like
if data length is 3
for(i=0;i<data.length;i++)
{
this.setState({ responseData:
<View>
<Text>{data[i].title}</Text>
<Text>Click to view more +</Text>
<View style={{height: 0}}>
<Text>View {i}</Text>
<Text>{data[i].requesttext}</Text>
<Text>{data[i].responsetext}</Text>
</View>
</View>
})
}
render(
<View style={styles.maincontainer}>
{this.state.reponseData}
</View>
)
//Make sure that I have written the above code just for an understanding.
Output
--------------------------
Test Title 1
Click to view more -
View 0
this is request
this is response
--------------------------
Test Title 2
Click to view more +
--------------------------
Test Title 3
Click to view more +
--------------------------
Here if I have data length is 3, I am creating 3 views and rendering it. Now my requirement is how can I show or set height auto (as there is no any display none property available in react native) that particular view which I am clicking to view more
Is there anything like id or class for reference to that particular view to set style ?
I have tried refs Refs to Components but its giving me error something like parent view node etc., and actually I dont know how to use it.
Also setting state is also not possible as this is dynamic.
Please let me know if you are not getting my point, or suggest me anything to accomplish this. Thanks!
Try this code:
constructor:
var views = [];
for(i=0;i<data.length;i++)
{
views.push(
<View ref={ref=>this['view_'+i]}>
<Text>{data[i].title}</Text>
<Text>Click to view more +</Text>
<View style={{height: 0}}>
<Text>View {i}</Text>
<Text>{data[i].requesttext}</Text>
<Text>{data[i].responsetext}</Text>
</View>
</View>
}
}
this.state = {views};
render:
render(
<View style={styles.maincontainer}>
{{this.state.views}}
</View>
)
To hide any view:
onPress() {
const views = this.state.views;
// remove item that you want to hide here from views array
this.setState({views})
}
Try like below, split in to two components which will solve your issue.
Let say you have a data like below, Take the below as an example case for your issue
const sampleJson = [
{
id: 1,
name: "Green Tea",
description: "This is Green Tea",
imageurl: "https://www.mozismenu.com/wp-content/uploads/2017/04/Chicken-Keema-Samosa-0.jpg"
},
{
id: 2,
name: "Burger",
description: "This is Burger",
imageurl: "https://www.mozismenu.com/wp-content/uploads/2017/04/Chicken-Keema-Samosa-0.jpg"
},
{
id: 3,
name: "Pizza",
description: "This is Pizza",
imageurl: "https://www.mozismenu.com/wp-content/uploads/2017/04/Chicken-Keema-Samosa-0.jpg"
}
]
//HomePage Component
import Home from "../components/Home";
export default class HomePage extends Component{
render(){
return(
<ScrollView style={styles.container1}>
{ sampleJson.map((data, index) => {
return(
<View style={styles.container} key={data.id}>
<Text style={styles.welcome}>{data.name}</Text>
<Home display={false} data={data}/> //Here i'm sending the prop display as false initially for every view, and also sending the data as prop data.
</View>
)
})
}
</ScrollView>
)
}
}
const styles = StyleSheet.create({
container1: {
flex: 1,
backgroundColor: '#F5FCFF',
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
welcome2: {
fontSize: 16,
textAlign: 'center',
margin: 5,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
container3: {
backgroundColor: '#0098cd',
display: "none"
}
});
//Home Component
export default class Home extends Component{
constructor(props){
super(props);
this.state = {
show: this.props.display, //Each one will depend on its own state
data: this.props.data
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome} onPress={()=> this.setState({ show: !this.state.show})}>Click to view more +</Text> //It will set the flag is false if true and will set as true if false.
//If the show prop in state is false, it renders null
{ this.state.show === true
? ( <View style={styles.container3}>
<Text style={styles.welcome2}>View </Text>
<Text style={styles.welcome2}>{this.state.data.description}</Text>
</View>
)
: null
}
</View>
);
}
}
Related
I followed the tutorial Here to set up a drawer navigator for my app and I'm doing pretty much everything the same as this guide mentions but my output is something like this
According to the guide though, and according to my code there should be text in the middle of the white empty screen. This makes me think that the View tag of my home file is not working or it's not rendering for some reason but the render function does get called though, i see the logs and the console.log inside the function does show up there, so I just can't figure out what the issue is here.
Here's my code:
Home.js
class Home extends Component{
render() {
console.log("I AM HERE")
return (
<View style={styles.container}>
<Text style={styles.text}>Home Page</Text>
</View>
)
}
}
styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 20,
alignItems: 'center',
marginTop: 50,
justifyContent: 'center',
},
text: {
fontSize: 50,
color: 'red'
}
})
HomeRoute.js
const ROUTES = createStackNavigator({
[ROUTE_NAMES.HOME]: {
screen: Home,
navigationOptions: ({ navigation }) => ({
title: 'Home',
headerLeft: <SideDrawer navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
});
const HOME_ROUTES = createAppContainer(ROUTES);
export default HOME_ROUTES;
SideDrawer.js
export default class NavigationDrawerStructure extends Component {
toggleDrawer = () => {
this.props.navigationProps.toggleDrawer();
};
render() {
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity onPress={this.toggleDrawer.bind(this)}>
{/*Donute Button Image */}
<Image
source={drawerImage}
style={{ width: 25, height: 25, marginLeft: 5 }}
/>
</TouchableOpacity>
</View>
);
}
}
There is quite a difference between CSS flexbox and the one implemented by Facebook. Lots of things in common but defaults are very different. Specifically:
Everything is displayed: flex by default. All the behaviors of block and inline-block can be expressed in term of flex but not the opposite.
flex: attribute is only used when at the same level there are few components with different flex values (flex: 1, flex: 3) means that the second element should be 3 times bigger than the first one. flex attribute is the only one supported (no grow/shrink support).
More info: yoga
Do you have an App.js file ? I don't see it in your post. If not, you should add the code below:
import React from 'react';
import { View } from 'react-native';
import HomeRoute from './your_path/HomeRoute.js';
export default class App extends React.Component {
render() {
return (
<View style={{ flex: 1 }}>
<HomeRoute/>
<FlashMessage position="top" />
</View>
);
}
}
Otherwise I will be curious to glance your App.js.
I'm very new to react-native.
can any one please tell me how to pass data to another screen using react-native-router.
I have a flatlist when a list item is clicked it will display an alert meassage , when i click on ok button it should display the RxNumberin next screen.enter image description here
here is my full class
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
FlatList,
Image,
Alert
} from 'react-native';
import { Actions } from 'react-native-router-flux';
import colors from '../styles/colors';
class MedicineFlatList extends Component {
constructor(props) {
super(props);
this.state = {
refreshing: false,
};
}
componentDidMount() {
fetch('https://api.myjson.com/bins/96ebw')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
//dataSource: responseJson,
dataSource: responseJson.map(item => item.ReadyForPickups).reduce((acc, currValue) => { return acc.concat(currValue); }, [])
},
);
})
.catch((error) => {
console.error(error);
});
}
GetItem(RxNumber) {
Alert.alert(
'RxNumber',
RxNumber,
[
{ text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel' },
{ text: 'OK', onPress: (item) => Actions.listitem({ item: item.RxDrugName }) },
],
{ cancelable: false },
);
}
listItem=(item) => {
return (
<Text style={styles.itemName}>{item.RxDrugName }</Text>
);
}
keyExtractor = (index) => {
return index.toString();
}
renderItem = ({ item }) => {
return (
<View style={styles.itemBlock}>
<View style={styles.itemMeta}>
<Text style={styles.itemName}>{item.RxDrugName}</Text>
<Text style={styles.itemLastMessage} onPress={this.GetItem.bind(this, item.RxNumber)}>{item.RxNumber}</Text>
</View>
<View style={styles.footerStyle}>
<View style={{ paddingVertical: 10 }}>
<Text style={styles.status}>{item.StoreNumber}</Text>
</View>
<View style={{ justifyContent: 'center', alignItems: 'center' }}>
<Image source={require('../assets/right_arrow_blue.png')} />
</View>
</View>
</View>
);
}
renderSeparator() {
return <View style={styles.separator} />;
}
render() {
return (
<View style={styles.container}>
<FlatList
data={this.state.dataSource}
keyExtractor={this.keyExtractor}
renderItem={this.renderItem}
ItemSeparatorComponent={this.renderSeparator.bind(this)}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
paddingHorizontal: 30,
backgroundColor: colors.white
},
itemBlock: {
flexDirection: 'row',
paddingVertical: 15,
},
itemMeta: {
justifyContent: 'center'
},
itemName: {
fontSize: 16,
color: colors.black_two,
paddingBottom: 10
},
itemLastMessage: {
fontSize: 14,
color: colors.black_two,
},
status: {
fontSize: 14,
color: colors.blue,
fontWeight: 'bold'
},
separator: {
borderRadius: 4,
borderWidth: 1,
borderColor: colors.light_gray,
},
footerStyle: {
flexDirection: 'row',
flex: 1,
paddingVertical: 10,
justifyContent: 'flex-end'
}
});
export default MedicineFlatList;
Thanks everyone I got the answer.
if your are using react-native-router-flux which i recommend
https://www.npmjs.com/package/react-native-router-flux
it is something like that
Action.Screen2({id : 1})
and on screen2
this.props.id will be 1
and if your are using react navigation
read the doc it will help you
it is something like this
this.props.navigation.navigate('Screen2', {data: 'some-stuff'})
and you can access data in other screen like this.
this.props.navigation.state.params('data')
Tulasi, Roozbeh Mohammadzadeh is correct and answers your question with the use of react-native-router-flux; however, as you continue you may wish to explore using redux or another alternative Appstate system, there are a few.
Reason: Passing data will work for small projects, but larger projects passing up and down the grandparent, parent, child component chain becomes cumbersome and inefficient to troubleshoot and/or maintain.
But to answer your question about passing data using react-native-router see the following right above the Todos section : https://www.npmjs.com/package/react-native-router
The this.props.toRoute() callback prop takes one parameter (a JavaScript object) which can have the following keys:
name: The name of your route, which will be shown as the title of the
navigation bar unless it is changed.
component (required): The React
class corresponding to the view you want to render.
leftCorner:
Specify a component to render on the left side of the navigation bar
(like the "Add people"-button on the first page of the Twitter app)
rightCorner: Specify a component to render on the right side of the
navigation bar
titleComponent: Specify a component to replace the
title. This could for example be your logo (as in the first page of
the Instagram app)
headerStyle: change the style of your header for
the new route. You could for example specify a new backgroundColor
and the router will automatically make a nice transition from one
color to the other!
data: Send custom data to your route.
I've got a problem with my app. I'm trying to change style in my child component using states but unfortunately i dont get any results. I tried evrythig i know, but i dont know what is going on and why styles aren't changing at all
Here is parent :
constructor(props) {
super(props);
this.state = {
number: 1,
cords: [
],
choosenCords: [
],
style: {flex:1,flexDirection:'row',backgroundColor:'red'}
};
}
<View style={{ marginTop: 3 }}>
<ListItem style={this.state.style} test={this.state.test} title={item.timestamp} context={item.longtitude + " " + item.latitude} click={this.getData.bind(this, item.longtitude, item.latitude, item.timestamp)} />
</View>
getData = async(x, y, z) => {
let tempTab = []
tempTab.push(x)
tempTab.push(y)
tempTab.push(z)
const changeTest = this.state.test * (-1)
await this.setState({
choosenCords: [...this.state.choosenCords, tempTab],
style: {flex:1,flexDirection:'row',backgroundColor:'blue'}
})
}
}
This fragment of code represent changing style onPress. "choosenCords" are changing, but "style" don't.
Here is child:
class ListItem extends Component {
constructor(props) {
super(props);
this.state = {
test:this.props.test
};
}
render() {
return (
<View style={this.props.style}>
<Image
source={require('../Images/gps.png')}
style={{ borderWidth: 3, borderColor: '#7887AB', borderRadius: 50, marginLeft: 15, marginTop: 10 }}
/>
<View style={{ flex: 1, flexDirection: "column", marginBottom: 15, marginLeft: 10 }}>
<Text style={{ marginLeft: 10, fontSize: 16 }}>
{
"Timestamp: " + this.props.title
}
</Text>
<Text style={{ marginLeft: 15, fontSize: 15 }}>
{
"Cords:" + this.props.context
}
</Text>
</View>
<TouchableHighlight
underlayColor={'transparent'}
onPress={
this.props.click
}>
<Image
source={
require('../Images/check.png')
}
style={{ marginRight: 20 }}
/>
</TouchableHighlight>
</View>
);
}
Could someone help me with that?
You have to do like this:
const customStyle= this.state.test ? styles.custom_1: styles.custom_2
return <View
style={[ styles.anyStyle, customStyle]}
/>;
Define your custom style variable, set it based on state, then use it as an array for your element.
The child component does not automatically update when the state of the parent component changes. You'll need to update the state of the child component manually when the parent sends new props.
//in child component
componentDidUpdate(previousProps, previousState){
if(previousProps.style !== this.props.style){
//update child state here
this.setState({style: this.props.style})
}
}
Now instead of using "style={this.props.style}" in the child, use "style={this.state.style}"
It is happening because when you update your state, child component will not update automatically. you will get new updated value in componentWillReceiveProps() method.
your ListItem class will be like below:
class ListItem extends Component {
constructor(props) {
super(props);
this.state = {
test:this.props.test,
style:'' // take style into your state
};
}
componentWillMount(){
this.setState({style: this.props.style}) //set style
}
componentWillReceiveProps(newProps){
//called when you update style
if(newProps.style !== this.props.style){
this.setState({style: newProps.style})
}
}
render() {
return (
<View style={this.state.style}> //set style for views from state
// add your views here
</View>
);
}
}
So I got this piece of code, and I want to display the Spinner on the bottom of the screen, just right after the FlatList, but when the function displaySpinner is called nothing displays after the flatlist. I've tried many things like putting trying to display the Spinner on the top of the view and then give it a Top but it's not what I'm looking for.
By the way I'm new in the programming world and more on React Native so I hope everything makes sense to understand my problem
import React, { Component } from 'react';
import { FlatList, StyleSheet, View, Text, Image } from 'react-native';
import axios from 'axios';
import moment from 'moment';
import Card from './Card';
import CardSection from './CardSection';
import Spinner from './Spinner';
class ArticleList extends Component {
state = { articles: [],
refreshing: false,
isLoading: false,
};
componentWillMount() {
this.loadArticles();
}
currentOffset = 0;
reloadContent() {
this.setState({
isLoading: true
});
this.currentOffset += 20;
console.log(this.currentOffset);
this.loadArticles();
}
loadArticles = () => {
const { articles } = this.state;
console.log(this.currentOffset);
axios.get(`https://sportsoftheday.com/wp-json/wp/v2/posts?per_page=20&offset=${this.currentOffset}`)
.then(res =>
this.setState({
articles: this.currentOffset === 0 ? res.data : [...articles, ...res.data],
isLoading: false,
}))
.catch(err => {
console.error(err);
});
};
displaySpinner() {
if (this.state.isLoading === true) {
return <Spinner size='large' />;
}
}
//Apply removeClippedSubviews for eliminating useless data on the screen
render() {
const { articles } = this.state;
this.date = this.date;
this.fimg_url = this.fimg_url;
return (
<View>
<FlatList
data={articles}
renderItem={({ item }) => (
<Card>
<CardSection>
<View style={styles.thumbnailContainerStyle}>
<Image
style={styles.thumbnailStyle}
source={{
uri: item.fimg_url,
cache: 'only-if-cached'
}}
/>
</View>
<View style={styles.headerContentStyle}>
<Text style={{ color: '#B2B2B2' }}>
{moment(item.date).format('dddd, Do MMMM YYYY')}</Text>
<Text
numberOfLines={3}
style={styles.headerTextStyle}
>
{item.title.rendered}
</Text>
</View>
</CardSection>
</Card>
)}
keyExtractor={i => i.id}
onEndReached={this.reloadContent.bind(this)}
onEndReachedThreshold={0.1}
/>
{this.displaySpinner()}
</View>
);
}
}
const styles = StyleSheet.create({
headerContentStyle: {
flexDirection: 'column',
justifyContent: 'space-around',
flex: 1
},
headerTextStyle: {
textAlign: 'justify',
fontSize: 18,
color: 'black',
marginRight: 15
},
thumbnailStyle: {
height: 70,
width: 70
},
thumbnailContainerStyle: {
justifyContent: 'center',
alignItems: 'center',
marginLeft: 10,
marginRight: 10
},
imageStyle: {
height: 300,
flex: 1,
width: null
},
});
export default ArticleList;
First things first, you should always avoid rendering a view/component directly in the renderItem = { } prop of your FlatList. Always send a function that is bounded to your current context that returns a component renderItem = {this._renderItem.bind(this)} or renderItem = {() => renderItem()}. This is not an issue but a usual practice that keeps the code clean and professional. Just a suggestion since you mentioned you're new to RN.
Coming to your question, the spinner shall show up once you wrap your Spinner inside a View component. You can do this either by wrapping your function call <View> {this.displaySpinner()} </View> or return a component that is already wrapped in a View <View> <Spinner/> </View>.
To make this even more effective, wrap everything including your flatlist but excluding your Header if you have one (Obviously) inside a View and give it a style of flex flex: 1 with a direction of column 'flexDirection: 'column'. Now you can justify your content with justifyContent: 'space-around' or 'space-between' whichever works for you.
Final point I'd like to make is again a suggestion. I've been working on RN for a while now but I still find designing the UI one of the most tedious tasks. Hot Reloading helps but not much. To track your UI changes on the screen, you can give the style borderColor: 'red', borderWidth: 1 to your views. This will help you a lot. It sure helps me.
I hope this helps.
Best of luck
Wrap that spinner in a view like View style = {{ position: "absolute", bottom: 0, width: '100%'}}
{this.displaySpinner()}
Close View
Hey Everyone :) This is my first post here, hope I am doing everything correctly!
I am currently working on a school project and using react-native for some weeks now.
My Problem:
I have the file data.js:
const cardOne_1 = require("../images/Vergleiche/Eisbär.jpg");
const cardTwo_1 = require("../images/Vergleiche/Android.jpg");
const cardThree_1 = require("../images/Vergleiche/Han_Solo_Alt.jpg");
const cardOne_2 = require("../images/Vergleiche/Gorilla.jpg");
const cardTwo_2 = require("../images/Vergleiche/Apple.jpg");
const cardThree_2 = require("../images/Vergleiche/Han_Solo_Jung.jpg");
export default[
{
image: cardOne_1,
image2: cardOne_2,
text: '53%',
text2: '47%',
title: 'Icebear vs Gorilla',
check: false,
},
{
image: cardTwo_1,
image2: cardTwo_2,
text: '19%',
text2: '81%',
title: 'Android vs IOS',
check: true,
},
{
image: cardThree_1,
image2: cardThree_2,
text: '70%',
text2: '30%',
title: 'Han Solo',
check: false,
},
];
My Homescreen contains two of these Deckswipers (For better clarity I will show here only the code for the first one), which are used to compare two images:
Homescreen - With two DeckSwiper
import data from '../Data.js';
export default class SwipeCards2 extends Component {
_onSwipeLeft() {
this._deckSwiper1._root.swipeLeft();
this._deckSwiper2._root.swipeRight();
}
_onSwipeRight() {
this._deckSwiper2._root.swipeLeft();
this._deckSwiper1._root.swipeRight();
}
render() {
return (
<Container style={{ backgroundColor: '#ffffff' }}>
<View>
<DeckSwiper
ref={mr => (this._deckSwiper1 = mr)}
dataSource={data}
onSwipeRight={() => this._deckSwiper2._root.swipeLeft()}
onSwipeLeft={() => this._deckSwiper2._root.swipeRight()}
looping={true}
renderEmpty={() => (
<View style={{ alignSelf: 'center' }}>
<Text>Das war´s!</Text>
</View>
)}
renderItem={item => (
<Card
style={{
elevation: 3,
height: 335,
justifyContent: 'center',
width: Dimensions.get('window').width + 1,
marginLeft: -1,
marginTop: 0,
}}>
<TouchableWithoutFeedback onPress={() => this._onSwipeRight()}>
<CardItem cardBody style={{ alignItems: 'center' }}>
<Image
style={{
resizeMode: 'cover',
flex: 1,
height: 335,
}}
source={item.image}
/>
</CardItem>
</TouchableWithoutFeedback>
</Card>
)}
/>
</View>
</Container>
);
}
}
I want to set the state "check" in data.js to true, everytime the user does swipe to the right.
A Third Screen renders a List component, which should show the previous made decisions of the user. This list is based on "check" of data.js.
Screen 3 - List of all the decisions
I tried for almost three days and can not find any good solution!
Do you have any suggestions how to achieve this?
Thanks :)
I'm not sure how things work with this DeckSwiper component but since you are importing a static data, if you need to change the data you need to clone it and then change it. Assigning data clone to a state variable and then giving it to the component will reflect the changes to the component.
To change a property on a specific object in your array you also need an unique identifier like an ID or similar.
Example
import data from '../Data.js';
export default class SwipeCards2 extends Component {
constructor(props) {
super(props);
// clone the static data to state
this.state = {
data: [...data]
}
}
changingCheckFunction(obejctsUniqueId) {
this.setState((prevState) => {
// find the object's id
const itemIndex = prevState.data.findIndex(x => x.id == obejctsUniqueId);
// copy the item and assign the new checked value
const newItem = Object.assign({}, prevState.data[itemIndex], { checked: !prevState.data[itemIndex]});
// copy the previous data array
const newData = [...prevState.data];
// set the newItem to newData
newData[itemIndex] = newItem;
// return the new data value to set state
return { data: newData };
});
}
_onSwipeLeft() {
this._deckSwiper1._root.swipeLeft();
this._deckSwiper2._root.swipeRight();
}
_onSwipeRight() {
this._deckSwiper2._root.swipeLeft();
this._deckSwiper1._root.swipeRight();
}
render() {
return (
<Container style={{ backgroundColor: '#ffffff' }}>
<View>
<DeckSwiper
ref={mr => (this._deckSwiper1 = mr)}
dataSource={this.state.data}
onSwipeRight={() => this._deckSwiper2._root.swipeLeft()}
onSwipeLeft={() => this._deckSwiper2._root.swipeRight()}
looping={true}
renderEmpty={() => (
<View style={{ alignSelf: 'center' }}>
<Text>Das war´s!</Text>
</View>
)}
renderItem={item => (
<Card
style={{
elevation: 3,
height: 335,
justifyContent: 'center',
width: Dimensions.get('window').width + 1,
marginLeft: -1,
marginTop: 0,
}}>
<TouchableWithoutFeedback onPress={() => this._onSwipeRight()}>
<CardItem cardBody style={{ alignItems: 'center' }}>
<Image
style={{
resizeMode: 'cover',
flex: 1,
height: 335,
}}
source={item.image}
/>
</CardItem>
</TouchableWithoutFeedback>
</Card>
)}
/>
</View>
</Container>
);
}
}