In React Native I have a Screen that shows a short story consisting of up to 1500 words. These words are clickable (and can have a border) so each one of them is wrapped in a View and TouchableOpacity.
The performance when opening the screen is way slower than I expect it to be, rendering a Screen with 1400 Words can take up to 5 seconds. Doing the same things in vanilla js on a website takes far less than a second.
This is my code. I have an array 'content' containing all the words and in the render function I use map to loop over them and create the TouchableOpacitys/Views.
return (<View style={styles.hanziRow2}>
{content.map(word => {
return (
<TouchableOpcaity onclick={() => this.openWord(word)}>
<View style={[styles.hanziBlock, { backgroundColor: 'transparent', paddingLeft: 0, paddingRight: 0, marginLeft: 0, marginRight: 0 }]}>
<Text style={styles.hanziBlockUpper}>{word}</Text>
</View>
</TouchableOpcaity>
)})
}</View>)
Yes, its obvious that the performance will be slow because you are rendering a lot of TouchableOpacitiy components at once.
So in order to fix it, you should limit the number of components that are rendered on the screen at once.And its quite obvious also that why would you like to render those components which ain't visible on the screen at that time.
For implementing it, you can use Flatlist component to limit the rendering.
It will increase the performance of you app.
Related
In my React Native Project, I am trying to make some kind of lists using Flatlist or sometimes using map method, for executing JSX Element. I am getting the result correctly, But there is a bit of a problem in separate.
Let's take chatting app example, When we open WhatsApp there are a lot of people showing up, but there is also a tiny separator after each item, That looks great, Now exactly when I try to put that separator in my React Native application using ItemSeparatorComponent attribute in Flatlist, It's working but still in some places, meaning in some items that separator not showing up, its looks missing, it feels that there is no border/separator. And actually what's going on is that, the below item from that separator which is hidden or which height looks smaller than others, that below View go a little bit towards the upside, so the separator gets to hide, That's the main problem, Why is that happening, I tried everything but still, I am getting that UI problem.
Here is code example:
<FlatList
data={actionSheet._data}
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
keyExtractor={(_, index) => index}
renderItem={({item, index}) => <ActionSheetClickableItem data={item} index={index}/> }
ItemSeparatorComponent={() => (
<View
style={{
height: 1,
width: '100%',
backgroundColor: 'red'
}}
/>
)}
/>
OR
<ScrollView>
{
actionSheet._data.map((item, index) => (
<>
<ActionSheetClickableItem data={item} index={index} key={index}/>
<View
style={{
height: 1,
width: '100%',
backgroundColor: 'red'
}}
/>
</>
))
}
</ScrollView>
So according to the above code, I know for sure, that everything is correct, But why is that separator get hidden, If we look at this picture in the area of the green rectangles, there is no border showing up, Why... I want to show it here, I tried to put zIndex property, that trick working correctly but that isn't the solution, It have to correct view as we expecting, why its behave like this, any solution??????
I was facing the same issue.
That might be with Emulator or Your screen.
You can use also increase the height of itemSeparater or make the background color more darker.
If you check it in real device then it displays all the separaters.
I am trying to display vertical scroll indicator always. Because I have 4 pages in my screen, But, After loading screen and scroll first page, The vertical scroll indicator is disappearing which is default behaviour of scrollview. So, I have try to show some flashScrollIndicators() But, still it is disappearing.
setScrollView = (scrollView) => {
// NOTE: scrollView will be null when the component is unmounted
this.scrollView = scrollView;
this.scrollView.flashScrollIndicators();
};
render() {
return (
<ScrollView ref={this.setScrollView} style={{ marginTop: 10, flexGrow: 1, flex: 1 }} contentInset={{ bottom: 20 }}>
);
}
Any suggestions, My requirement is I have to display scroll indicator always in my screen.
flashScrollIndicators() will flash the indicator for one or two seconds. You would need to keep calling it to see it (for example with setInterval). But this will make it flash like a Christmas tree, since it will flash every-time it is called, not stay solid.
If what you want the bar to be always solid, then you could use my suggestion for iOS (without native code). Android has the persistentScrollbar prop, which is simple enough to use.
I got a FlatList with numColumns={2}, inside this FlatList, I render a Native-Base Card item.
The idea is to have a list of cards and each of those, occupying the 50% of the parent container.
But I realized that if for example I have 3 items, the item below would occupy the 100% of the width due to flex: 1 on the card style.
How can I make the item that is alone to go only up to 50% width no matter what?
This is my code:
render() {
return (
<View>
<FlatList
numColumns={2}
style={ styles.cardContainer }
keyExtractor={ this._keyExtractor }
data={ this.state.itemList }
renderItem={ this._renderItem }
>
</FlatList>
</View>
);
}
The styles being applied:
cardContainer: {
flex: 1,
flexDirection: 'column'
},
card: {
flex: 1,
margin: 10,
flexBasis: '50%'
},
_renderItem is just a <Card></Card> with the style={ card } on it. I can post it if needed as well. But no major styling in there except for the inner elements.
Also, I noticed that when I scroll this FlatList, and if the list elements aren't taking the 100% of the vertical space, it looks like if it had an overflow: hidden with the max height of the parent container, how can I make this FlatList to be also 100% height no matter what?
This is what it's happening, not the desired outcome.
Thanks in advance.
After checking the possible duplicated that Rocky's suggested. I found a solution for my specific case and I also think it's the cleanest solution so far. Kudos to #Emilius Mfuruki.
There were a few other recommendations but adding flex: 1/n on the iterated item worked for me. So if you have 2 columns, it would be 1/2, if 3 would be 1/3 and so on.
Hope this helps others.
I really do not have a ton of code for this so this might not be the perfect place to ask this.. but I need help trying to figure out some sort of a solution..
I have an array of URL's stored in the state.
<TouchableHighlight style={ styles.container } onPress={this.screenTap.bind(this)}>
<Image source={{uri: this.state.picCollection[this.state.counter].Picture }} style={styles.backgroundImage} >
<View style={ styles.loginForm }>
<Button onPress={this.screenTap.bind(this)} style={{ alignSelf: 'center', marginTop: 20, marginBottom: 20 }}>Create</Button>
<Text style={ styles.text }>Some text</Text>
</View>
</Image>
</TouchableHighlight>
This screenTap function that is the onPress just incriments, changing which url we are loading from this.state.picCollection
How this code above works is everytime its pressed it is intended to switch the image show. However, when I do that instead of seamlessly transitioning it shows this white screen before loading.
I am guessing this is because everytime I do this I am reloading the state. However I am not really sure how I would approach something like this.
Any advice would be amazing!
When you change one of the props or state variables in React, the affected components re-render. From the browser's point of view, one image disappears and another one appears in it's place.
What this means for you is that each time you change the URL, an image that wasn't there before now is, and it needs to be loaded anew. I'm very certain that's what the white flash is - the browser loading the new image.
Fortunately, you can load images without showing them. This page offers some good techniques, but the most basic is to just have N image tags with each of the images you want to load. Create a CSS class that consists of display: none and apply it to those images. Ta-da! The images are loaded and cached, but the uses doesn't see any of it.
Then, when your Image component changes its src tag to one of the Images you prepared earlier, the browser already has the image in memory, so it should load immediately. (Just make sure that it is exactly the same URL!)
What is the exact purpose of setting rule flex: 1 to many React Native components?
Very often I can see this rules applied to different components. Sometimes this rules obviously redundant. Sometimes no obviously, but layout seems working well without it.
So, what exactly this rule suppose to do?
If the component is rendering fine without using flex: 1 it is obviously not needed. You might as well want to remove the unwanted style. What flex: 1 does is that it tells the component to occupy as much space as it can.
For example:
<View style={{ flex: 1, backgroundColor: '#cccccc' }}>
<Text>Hi</Text>
</View>
This will span the whole screen.
However, if you place another View at the same level in the DOM, both of the Views will occupy equal space i.e. the screen will be divided in two parts.
Like this:
<View style={{ flex: 1 }}>
<View style={{ flex: 1, backgroundColor: '#cccccc' }}>
<Text>View one</Text>
</View>
<View style={{ flex: 1, backgroundColor: '#eaeaea' }}>
<Text>View two</Text>
</View>
</View>
I agree that flexbox is a little bit confusing. But once you get the hang of it, you'll learn how to manipulate the views.
Edit: Always wrap child components with a parent component in order to avoid potential runtime errors.
For layout React Native uses flexbox because display: flex; is extremely well-suited for creating responsive layouts across various screen sizes and devices. All the attribute names and values are listed in the React Native docs.
In other words, instead of using display: block with various floats your layout should be created using flexbox rules.
Modus Create did a nice tutorial on Flexbox in React Native.
Specifically, that rule:
flex: 1
is telling the element to grow to fill the available space.