React Native View not displaying anything - react-native

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.

Related

I'm trying to load all the images as a scrollable menu but can't figure out how

I'm new to react native, I am trying to get a menu composed of logos that someone could just scroll down then tap one to go into more detail about it.
So I have my App.js file like so:
import React from 'react';
import {
StyleSheet,
View,
Image,
ScrollView,
Text
} from 'react-native';
import getImageForRestaurant from './utils/getImageForRestaurant';
import Avatar from './components/Avatar';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
restaurants: 'buffalo',
};
}
render() {
const {
restaurants
} = this.state;
return (
<View style={styles.appContainer}>
<View style={styles.titleContainer}>
<Text style={styles.title}>Title</Text>
</View>
<ScrollView style={styles.timerlist}>
<Avatar
initials="KC"
size={75}
source={getImageForRestaurant(restaurants)}
backgroundColor={'blue'}
onPressLinkImage={() => {
console.log('Pressed!');
}}
/>
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
appContainer: {
flex: 1,
justifyContent: 'center',
},
titleContainer: {
paddingTop: 35,
paddingBottom: 15,
borderBottomWidth: 1,
borderBottomColor: '#D6D7DA',
},
title: {
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
timerList: {
paddingBottom: 15,
},
container: {
flex: 1,
backgroundColor: '#34495E',
},
imageContainer: {
flex: 0,
},
image: {
flex: 1,
width: 75,
height: 75,
resizeMode: 'contain',
},
});
The getImageForRestaurant() method works as intended if I make it inside an <Image/> but if I try to make it the source of my "Avatar" component then it won't work.
My getImageForRestaurant.js file is just this:
const images = {
buffalo1: require('../assets/restaurants/logo1.jpeg'),
buffalo: require('../assets/restaurants/logo2.png'),
buffalo2: require('../assets/restaurants/logo3.jpeg'),
};
export default restaurants => images[restaurants];
And finally my Avatar.js is as follows:
import {
ColorPropType,
StyleSheet,
Text,
View,
Image,
TouchableOpacity
} from 'react-native';
import PropTypes from 'prop-types';
import React from 'react';
import getImageForRestaurant from '../utils/getImageForRestaurant';
export default function Avatar({
size,
backgroundColor,
initials,
source,
onPressLinkImage,
}) {
const style = {
width: size,
height: size,
borderRadius: size / 2,
backgroundColor,
};
return (
<View style={[styles.container, style]}>
<TouchableOpacity onPress={onPressLinkImage}>
<Text style={styles.text}>{initials}</Text>
<Image source={require(getImageForRestaurant(source))} />
{/*<Image source={require("../assets/restaurants/logo1.jpeg")} />*/}
</TouchableOpacity>
</View>
);
}
Avatar.propTypes = {
initials: PropTypes.string.isRequired,
size: PropTypes.number.isRequired,
source: PropTypes.number.isRequired,
backgroundColor: ColorPropType.isRequired,
onPressLinkImage: PropTypes.func.isRequired,
};
const styles = StyleSheet.create({
container: {
alignItems: 'center',
justifyContent: 'center',
},
text: {
color: 'white',
},
});
So if I just do an Image source, (the commented part) it works as a regular image, but then I need to hard-code the actual url and what I want is to just load all images one next to the other in a scrollable grid. Haven't been able to figure out how to do what I want. Could someone please point me in the right direction?
While Edison makes a good point about good practices, I believe your problem is that you are just requiring the image twice. The output of the require() is what you need to pass to the Image component. You are doing require of a require.
<Image source={require(getImageForRestaurant(source))} />
Probably just changing to this should work:
<Image source={getImageForRestaurant(source)} />
It’s a bad practice to generate url inside the source prop. Always make sure that the necessary URL is built before its passed inside source prop. You can use a variable to build your URL and then pass it to source prop. (In your case, image is imported inside helper function and hence I will use image variable)
const image = getImageforRestaurant(source)
<Image source={image} />
When you want to load images from the internet do it like this.
const link = ‘http://example.com/image.png’
<Image source={{uri: link}} />

how to pass data from one screen to other screen using react-native-router

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.

Custom navigator menu in React Native

I'm new in React Native and have a project with a kind of menu on the right side (5 buttons) on several screens. What I want to do is to use this menu only once for the whole app with a container, and change the content of the container according to the selected button, like in Android with fragment and fragmentManager.replace...
Screens and menu are developed but I really don't know how to mix everything properly .
I read doc about react-navigation (https://reactnavigation.org/docs/en/custom-navigators.html) but do not understand well everything. However I just need a kind of TabNavigator with custom Tab on the ride side.
Please help me.
Not sure what do you mean, but i think you could try something like this:
const CustomDrawer = createDrawerNavigator({
Screen1: {
screen: Screen1,
},
Screen2: {
screen: Screen2,
},
})
const RootNavigator = createStackNavigator({
MainScreen: {
screen: MainScreen,
},
CustomDrawer: { screen: CustomDrawer }
},
{
initialRouteName: 'Init',
})
Basically, you can create a Drawer on the right/left. And add your 5 screens on it, then you will use the drawer to navigate between those screens. Plus you'll instantiate your drawer on a stackNavigator which will handle the navigation. You can also set your main screen on it and everything else.
I think you want drawer in react native app using react-navigation..
use createDrawerNavigator it providers you to custom design your side bar
createDrawerNavigator({
screen: {..your screen stack here...}
}, {
headerMode: 'none',
gesturesEnabled: false,
contentComponent: DrawerContainer, /// DrawerContainer is custom component container for all tabs
drawerBackgroundColor: 'transparent',
drawerWidth: 240,
useNativeAnimations: true
});
DrawerContainer .js :---
export default class DrawerContainer extends React.Component {
render() {
return (
<View style={{flex:1}}>
<TouchableOpacity
style={{borderBottomColor: '#fff', height: 40}}
onPress={() => this.props.navigation.navigate('screen name')}
>
<Text style={{color: '#FFFFFF',fontSize: 18}}
type='h5White'>your tab name</Text>
</TouchableOpacity>
</View>
);
}
}
for more detail go to https://medium.freecodecamp.org/how-to-build-a-nested-drawer-menu-with-react-native-a1c2fdcab6c9
go for this medium tutorial
https://medium.com/#mehulmistri/drawer-navigation-with-custom-side-menu-react-native-fbd5680060ba
create custom side bar always fixed:---
Don't use drawer. I m making it by using hoc (Higher-Order Components)
Fist make Higher-Order Components as sidebar.js
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity
} from 'react-native';
const withSidebar = WrappedComponent => class extends Component {
constructor(props) {
super(props);
this.state = { isConnected: true };
}
render() {
return (
<View style={styles.container}>
<View style={{width:50, top:20, backgroundColor: 'grey',}}>
<TouchableOpacity
style={styles.menu}
onPress={() => console.log('code')}
>
<Text style={styles.menuText} type='h5White'>first</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.menu}
onPress={() => console.log('code')}
>
<Text style={styles.menuText} type='h5White'>second</Text>
</TouchableOpacity>
</View>
<View style={{flex:1, backgroundColor: 'red', top:20}}>
<WrappedComponent {...this.props} />
</View>
</View>
);
}
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
flexDirection: 'row',
},
welcome: {
flex: 1,
margin: 20,
backgroundColor: 'orange',
margin: 10,
textAlign: 'center',
fontSize: 20,
paddingTop: 70,
},
menu: {
paddingHorizontal: 7,
borderBottomWidth: 1,
borderBottomColor: '#fff',
height: 40,
justifyContent: 'center'
},
menuText: {
justifyContent: 'center',
color: '#FFFFFF',
fontSize: 10,
fontWeight: 'bold'
},
});
export default withSidebar;
Now only connect your screen with this hoc:--
import sidebar.js in your screen as
import withSidebar from 'sidebar'
export default connect(mapStateToProps, mapDispatchToProps)(withSidebar(yourScreenName));
This HOC is available for every screen where you want just use above syntax.
You can also put it in your root level component only once to get it for whole components (its over you how you implement this).

react native spinner doesn't display on bottom

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

Hide/Show dynamically created view - React Native

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>
);
}
}