FlatList does not render (it does not display on screen) - reactjs

I have a component that gets some data from firebase, stores it in an array "CompanyOffers" and should display it via a FlatList. The FlatList, along with other components are inside of a ScrollView. Everything above the FlatList is rendered and displays on the screen except for the FlatList itself. Whats going wrong ??
class CompanyDetails extends Component {
constructor(props) {
super(props);
...
this.state = {
loading: true,
CompanyOffers: [],
};
}
...
render() {
return (
<ScrollView>
<View>
<View>
<View>
<Image
source={{ uri: this.props.logo }}
/>
</View>
<View>
<Text>{this.props.companyName}</Text>
<Text>{this.props.description}</Text>
</View>
</View>
</View>
<FlatList
data={this.state.CompanyDetails}
renderItem={({ item }) => <Text>hello</Text> }
/>
</ScrollView>
);
}
}
export default CompanyDetails;
Note: I have styles for the components but removed them for the question.

I guess your array is CompanyOffers check once
<FlatList
data={this.state.CompanyOffers}
renderItem={({ item }) => <Text>hello</Text> }
/>

Related

Reloading an animation React-native-animatable library

guy's I'm using the react-native-animatable library. Basically, when I load my app the animation runs, however, when I go to another tab and return to the initial page the animation doesn't run anymore. I think it's because it' doesn't get reloaded anymore and I was wondering how to reload a component. As you can see the View has an animation prop which is the animation which has to be loaded.
import React, { Component } from 'react';
import { Text, Button, StyleSheet, Image, ImageBackground, TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import LinearGradient from 'react-native-linear-gradient';
import {Fonts} from '../components/Fonts';
import { createAnimatableComponent, View, } from 'react-native-animatable';
class Home extends React.Component {
render() {
return (
<View style={styles.container}>
<View animation='bounceInLeft'
style={styles.container1}>
<View style={styles.card1}>
<ImageBackground
source={require('../images/pictures/runop.jpg')}
style={{width:'100%', height:200, }}>
<Text
style={{fontSize:30, alignSelf:'center', color:'white',
fontFamily:Fonts.Nunito}}
> Sport Schema's</Text>
</ImageBackground>
</View>
</View>
<View animation='bounceInRight' style={styles.container2}>
<View style={styles.card2}>
<Image
source={require('../images/pictures/foodop.jpg')}
style={{width:'100%', height:200}}/>
</View>
</View>
<View animation='bounceInLeft' style={styles.container3}>
<View style={styles.card3}>
<Image
source={require('../images/pictures/blogop.jpg')}
style={{width:'100%', height:200}}/>
</View>
</View>
</View>
);
}
}
Thanks for your help. I eventually got it to work with a different method.
I used the withNavigationFocus from react-navigation to get the isFocused props of the current screen. Then i just used an if statement if screen is focused then run animation else dont.
import {withNavigationFocus} from 'react-navigation';
class Profile extends React.Component {
constructor(props) {
super(props);
}
render()
// This checks if current screen is focused then run the animation otherwise dont.
{
if (this.props.isFocused && this.animation) {
this.animation.bounce(800)
}
return (
<View ref={(ref) => {this.animation = ref;}}
style={styles.container3}>
<View style={styles.card3}>
<Text> hii</Text>
</View>
</View>
);
}
}
});
export default withNavigationFocus(Profile); // <- dont forget this!!
If you are using react-navigation, below solution might work for you.
Create a function which would start the animation after some milliseconds and pass it to the next screen as params. Example,
SCREEN A
animateFunction() {
setTimeout(() => {
// start your animation
}, 100);
}
navigation.navigate(SCREEN_NAME, { startPrevScreenAnimation: animateFunction });
And in the next screen call that function when the component unmounts (componentWillUnmount()). Example,
SCREEN B
componentWillUnmount() {
this.props.navigation.state.params.startPrevScreenAnimation();
}
I said some milliseconds because you would want the animation to start once the screen transition is complete.
OR
Add a listener to your screen which fires an event when the screen is in focus.
if (this.props.navigation) {
this.willFocusSubscription = this.props.navigation.addListener(
'willFocus',
() => { // Run your animation },
);
}

React Native - Put child components into parent according to 'key' leads error

Here I am creating a react-native project which have installed react-navigation.
I have switch on the StackNavigator for pages across the application. Below is what I would like to archive.
I would like to use StackNavigator without using the provided header. Therefore I create a component <Header> like below:
export default class Header extends Component {
constructor(props) {
super(props);
}
detectKeyAndRender(item) {
if (item.key === "left") {
return <View style={leftContainerStyle}>{item}</View>;
} else if (item.key === "middle") {
return <View style={middleContainerStyle}>{item}</View>;
} else if (item.key === "right") {
return <View style={rightContainerStyle}>{item}</View>;
}
}
render() {
return (
<View key="header" style={headerContainerStyle}>
{ this.props.children.map((item) => ( this.detectKeyAndRender(item) )) }
</View>
);
}
}
Also for the common styles and container structure, I have created a component called <BaseContainer> like below:
import { getChildComponent } from 'helper.js';
export default class BaseContainer extends Component {
constructor(props) {
super(props);
}
render() {
return (
<SafeAreaView key="safe-area-view" style={safeAreaViewStyle}>
{ /* Please set the header from each page */ }
{ getChildComponent(this.props.children, "header") }
<View style={outerContainerStyle}>
<ScrollView contentContainerStyle={scrollViewStyle} alwaysBounceVertical={false}>
{ /* Page content goes in here */ }
{ getChildComponent(this.props.children, "content") }
</ScrollView>
</View>
</SafeAreaView>
);
}
}
And also the helper.js:
export function getChildComponent(children, key) {
return children.filter( (comp) => {
return comp.key === key;
});
}
Thus in other pages, I can call the header like below:
export default class FirstPage extends Component {
render() {
<BaseContainer>
<Header key="header">
<Text key="left">Left</Text>
<Text style={{color: '#fff', fontSize: 20}} key="middle">First Page</Text>
<Text key="right">Right</Text>
</Header>
<View key="content">
<Text>This is first page.</Text>
</View>
</BaseContainer>
}
}
export default class SecondPage extends Component {
render() {
<BaseContainer>
<Header key="header">
<Text key="left">Left</Text>
<Text style={{color: '#fff', fontSize: 20}} key="middle">Second Page</Text>
<Text key="right">Right</Text>
</Header>
<View key="content">
<Text>This is second page.</Text>
</View>
</BaseContainer>
}
}
This render method of <Header> will bring out an error but it's not fatal. The error is about the unique key:
Warning: Each child in an array or iterator should have a unique "key" props.
Check the render method of `Header`.
I know inside react native, every key should be unique (for performance issue).
Therefore I would like to ask is there any better method to put the specific child component into the header, or add the style according to a "key"? Appreciate for any help.
Please try to make the solution as simple as possible. Combine some common code together is what I would like to archive.
NOTE: I don't want to use the custom header inside react-navigation because the position it put is not what I want.
A simple way to get rid of the error would be to add a unique key to the View Components generated in detectKeyAndRender by adding a second parameter to it. So your function would be e.g. detectKeyAndRender(item, key).
Inside of the function simply add that key parameter to every returned View: <View key={key} ... />
Then when you actually map over the children, pass the index to the function:
{ this.props.children.map((item, i) => ( this.detectKeyAndRender(item, i) )) }
Unique keys should be given to each child element.
Header
export default class Header extends Component {
constructor(props) {
super(props);
}
detectKeyAndRender(item) {
/* you can use 'left,'middle' & 'right' as keys - they are different */
let { key } = item;
/* do validation on style hence you are not changing anything on view */
/* 'Conditional Operator' is used to simplify if...else...if...else */
let style =
key === "left"
? leftContainerStyle
: key === "middle"
? middleContainerStyle
: key === "right"
? rightContainerStyle
: middleContainerStyle /* default */;
return (
<View key={key} style={style}>
{item}
</View>
);
}
render() {
return (
<View key="header" style={headerContainerStyle}>
{this.props.children.map(item => this.detectKeyAndRender(item))}
</View>
);
}
}

react-native: react-navigation drawer labels

I want to have drawer labels/separators in the drawer navigator.
Somewhat like this
How would I do this?
Easy. What you are looking at is called contentComponent. Basically you will need to inject a contentComponent prop into your Drawer navigator.
contentComponent Component used to render the content of the drawer, for example, navigation items. Receives the navigation prop for the drawer. Read more here
import DrawerContent from '../app/components/DrawerContent'
const drawerConfiguration = {
initialRouteName: 'MainStackNavigatior',
headerMode: 'screen',
drawerWidth: deviceWidth / 1.38,
contentComponent: DrawerContent
}
Where contentComponent is just a ScrollView containing a list of customisable items.
class DrawerContent extends Component {
onItemPress(item) {
const { navigation } = this.props;
navigation.navigate(item.key);
}
renderDrawerItem(route) {
const { drawerItems } = this.props;
if (drawerItems.indexOf(route.key) > -1) {
return (
<TouchableOpacity style={styles.drawerItem} key={route.key} onPress={() => this.onItemPress(route)}>
<Text>{route.routeName}</Text>
</TouchableOpacity>
);
}
return null;
}
render() {
const { navigation, isFetching, drawerItemsTitle } = this.props;
return (
<View style={styles.container}>
{!isFetching && <View style={styles.drawerItemTitle}>
<Text style={styles.drawerItemTitleText}>{drawerItemsTitle}</Text>
</View>}
{!isFetching && <View>
{navigation.state.routes.map(route => this.renderDrawerItem(route))}
</View>}
{isFetching && <View style={styles.spinnerViewBg}>
<View style={styles.spinner}>
<ActivityIndicator
size="small"
animating
/>
</View>
</View>}
</View>
);
}
}
Here's a good example from Infinite Red. Tutorial link
As for the separators, it is basically a View with minimal height and certain width. I believe you can figure it out :) Good luck!

Touch handler not called with React Native

I just started learning React Native and ran into this: I've created a component which has a TouchableHighlight within it, and I assigned a handler function to it, but it doesn't seem like it is getting called. Here is my component:
import React, {Component} from 'react';
import {
Text,
View,
TouchableHighlight
} from 'react-native';
export default class Component1 extends Component<{}> {
componentWillMount() {
console.log("hi there");
this.setState({age: 22});
}
handlePress() {
this.setState(prevState => ({ age: prevState.age + 1 }));
console.log("updated age");
}
render() {
return (
<View>
<View>
<Text>
{this.props.name}
{"\n"}
{this.state.age}
</Text>
</View>
<View>
<TouchableHighlight onPress={() => this.handlePress}>
<View>
<Text>Become older</Text>
</View>
</TouchableHighlight>
</View>
</View>
);
}
}
When I tap the "become older" view nothing is logged to the terminal (I'm using react-native log-android.
Thank you for helping out :)
Inside the onPress, it should be a function. You are using arrow function so, you should call the function handlePress:
This part:
<TouchableHighlight onPress={() => this.handlePress}>
Should be:
<TouchableHighlight onPress={() => this.handlePress()}>
But if you are just calling the function, so you just need to pass it in like:
<TouchableHighlight onPress={this.handlePress}>
You have a syntax error.
<TouchableHighlight onPress={() => this.handlePress}>
should be
<TouchableHighlight onPress={() => this.handlePress()}>
or
<TouchableHighlight onPress={this.handlePress}>

Click Item in ListView React-Native not working

i am new in react-native and i want to press to to specific item in ListView, but when i click to item wich i want to select i didn't get console log message and i didn't get any errors so my code look like this
in renderRow my code look like this
renderRow(record) {
return (
<View style={styles.row}>
<TouchableHighlight onPress={() => this._pressRow()}>
<View style={styles.info}>
<Text style={styles.items}>{record.nom}</Text>
</View>
</TouchableHighlight>
</View>
);
}
and _pressRow function simple console log
_pressRow (rowID: number) {
console.log("clicked");
}
and render function
render() {
return (
<ScrollView scrollsToTop={false} style={styles.menu}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
/>
</ScrollView>
);
}
how can i resolve this issue and thanks.
Are you using the autobind-decorator? Using your code as is the _pressRow method won't be triggered. When I add the autobind decorator or change _pressRow into a fat-arrow function the console.log does work for me:
import React, { Component } from 'react'
import { View, TouchableHighlight, Text, ScrollView, ListView } from 'react-native'
_pressRow = (rowID: number) => {
console.log("clicked")
}
class App extends Component {
constructor(props) {
super(props)
this.dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
})
this.state = {
dataSource: this.dataSource.cloneWithRows([
{ nom: 'a' },
{ nom: 'b' },
]),
}
}
renderRow(record) {
return (
<View>
<TouchableHighlight onPress={() => this._pressRow()}>
<View>
<Text>{record.nom}</Text>
</View>
</TouchableHighlight>
</View>
)
}
render() {
return (
<ScrollView scrollsToTop={false}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
/>
</ScrollView>
)
}
}
export default App
change the this._pressRow() to this._pressRow.bind(this) if your function is in your Class
I used TouchableHighlight to wrap "un-pressable" component (accompany with changing this._pressRow to this._pressRow.bind(this)).
Moreover, some component (such as Text component) does not fill all the space of ListView row. So that onPress only works if you press right at text (it does not work if you press on the row location that does not have any text). So that it is useful to wrap with TouchableHighlight component.

Resources