React Native memory leak when rendering a list of Views - performance

I'm building a recording app and I'm trying to render a waveform. The waveform's data is simply an array of numbers with a max length of 100. I iterate through the waveform array and render 100 <View />'s like so:
<View style={{ width: screenWidth, position: 'relative' }}>
{
this.state.waveforms.map((waveform, i) => {
return (
<View
key={waveform.key}
style={{
position: 'absolute',
top: WAVE_FORM_MAX_HEIGHT - waveform.value + (waveform.value / 2) - WAVE_FORM_MAX_HEIGHT,
left: screenWidth - (i * TOTAL_WAVE_FORM_WIDTH),
width: WAVE_FORM_MAX_WIDTH,
height: waveform.value,
backgroundColor: '#CC0000',
borderRadius: 2
}}
/>
)
})
}
</View>
The number of views always stays the same but the RAM continues to increase. Any ideas?

Related

React-Native | I can't get the bg image to cover

I'm trying to fit my background image to cover the whole app but its not, even though i've tested most of similar threads here so any help is appreciated.
I've made some changes to the original source and added an arrow towards the left edge of the image that i was hoping to have at the edge when i open up the EXPO app on my phone, but i only see a few pixels of the arrow at the left edge.
**app.js**
function HomeScreen() {
return (
<ImageBackground source={require('./assets/bgImage.jpg')} style={styles.bgImage}>
<View>
<Text>Home Screen</Text>
</View>
</ImageBackground>
);
}
bgImage: {
flex: 1,
width: null,
height: null,
resizeMode: 'cover',
justifyContent: 'center',
alignItems: "center"
}
try this :-
import React from 'react';
import { ImageBackground, View, Text } from 'react-native';
const HomeScreen = () => {
return (
<ImageBackground source={require('../assets/apple.jpg')}
style={{
position: "absolute",
top: 0,
left: 0,
bottom: 0,
right: 0,
flex: 1,
alignItems: "center"
}}>
<View style={{
width: '90%',
height: 200,
backgroundColor: "red",
justifyContent: "center",
alignItems: "center",
}}>
<Text>Home Screen</Text>
</View>
</ImageBackground>
);
}
export default HomeScreen;
It is working fine.

React Native - Can't clickTouchableOpacity inside ImageBackground

I want create a rotate icon inside a image:
<ImageBackground style={stylesNative2.image} source={{ uri }} >
<TouchableOpacity onPress={ () => { alert("handler here") }} tyle={styles.rotateImageIcon}>
<Icon name='rotate-ccw' type='Feather' style={styles.rotateImageIcon} />
</TouchableOpacity>
</ImageBackground>
const stylesNative2 = StyleSheet.create({
image: {
zIndex: 0,
position: 'absolute',
height: h,
width: WIDTH,
resizeMode: 'cover',
transform: [{ rotate: this.state.imageRotation + 'deg' }]
}
});
const styles = StylesManager.getStyles({
rotateImageButton: {
backgroundColor: 'transparent',
elevation: 0,
zIndex: 1
},
rotateImageIcon: {
marginTop: '1rem',
marginLeft: '1rem',
fontSize: '1.7rem',
color: 'white',
}
});
The icon appear but the TouchableOpacity is not working.
Any idea why it's not working?
I think it's because ImageBackgroud have a pointerEvent like this one:
pointer-events: none;
http://facebook.github.io/react-native/docs/view#pointerevents
Can you try to wrap your <TouchableOpacity> on a <View>?
Mayby it's the zIndex...
A touchable opacity is transparent so you don't have to add zIndex on it.
When we add TouchableOpacity inside the ImageBackground .
We need to add the zindex greater than ImageBackground.
like zindex:100
Elements with a higher index will be placed on top of elements with a lower index. Note: Z index only works on positioned elements ( position:absolute , position:relative , or position: fixed

React Native LayoutAnimation scrollView container size

I have some components wrapped in a ScrollView and for some condition the bottom most component shouldn't render. When that happens, I use LayoutAnimation to hide it. The problem is that when the component disappear, the ScrollView jumps to the new content height directly, without any animation at all.
I want to use LayoutAnimation since I have screens where the contents height is unknown.
Example image
If you look at the image, when the button is pressed, the screen will instantly jump to the blue box without any animation.
state = { showGreenBox: false };
renderBottomBox() {
if (this.state.showGreenBox) {
return (
<View style={{ height: 300, width: 100, backgroundColor: 'green' }} />
);
}
}
render() {
return (
<ScrollView>
<View style={{ height: 300, width: 100, backgroundColor: 'red' }} />
<View style={{ height: 300, width: 100, backgroundColor: 'blue' }} />
{this.renderBottomBox()}
<TouchableOpacity
onPress={() => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
this.setState({ showGreenBox: !this.state.showGreenBox });
}}
>
<Text>Press to collapse green box</Text>
</TouchableOpacity>
</ScrollView>
);
}

Nest inside <Image> but behind the image

The problem I'm having is that the image inside the image, is on top of the outside image, the outside image is a half transparent image so I want it to be ON TOP of the nested image, as an overlay image, what can I do?
<Image
style={it}
source={require('../../img/Rarities/red.png')}
>
<View>
{
item[2] != null ?
<View style={{ width: 15, height: 15, backgroundColor: item[2].Color }} />
: null
}
<Image
style={{height:'70%',width:'70%'}}
source={{ uri: item[1].base64 }}
/>
</View>
</Image>
I tried:
changing the zIndex of the images didn't work..
In React Native, components are rendered in the order they are defined - therefore it can be tricky to reverse the order and render a parent on top of a child.
Instead, you can render the images as siblings, and use a parent container component with a little position: absolute trickery to get the images to align on top of each other.
For the following view structure:
<View style={styles.imageContainer}>
<Image source={{uri: image1}} style={styles.bottom} />
<Image source={{uri: image2}} style={styles.top} />
</View>
You can achieve this effect with following styles. See inline comments for explanation:
const styles = StyleSheet.create({
// The container controls the top image size
imageContainer: {
width: 200,
height: 200
},
bottom: {
// horizontal margin: (100% -width) / 2
marginHorizontal: '15%',
// vertical margin: (100% - height) / 2
marginVertical: '15%',
width: '70%',
height: '70%'
},
top: {
// positioned absolutely
position: 'absolute',
opacity: 0.5,
// full width/height of imageContainer
width: '100%',
height: '100%'
},
});
You can see it in action in this Snack demo.
I'm not sure that i understand what are you meaning correctly but you can use the Image components like this if you want to have them inside each other:
<View>
<Image
style={{flex:1}}
source={require('./img/favicon.png')}
/>
<Image
style={{height:'30',width:'30', position:'absolute'}}
source={require('./img/favicon.png')}
/>
</View>
Note: the Image sources and the dimensions should be replaced.

How to determine JS bottlenecks in React Native code?

I am adding a React Native Slider component to an existing app, and prefer to utilize its onValueChange prop so that as the user slides the knob left and right, a couple of Text components have their values updated in response to the Slider's current value.
On a first attempt this causes a significant amount of lag after letting go of the slider knob. StackOverflow isn't letting me embed the gif here so I'll leave the link instead: http://imgur.com/sEowpZt
When I comment out onValueChange and use onSlidingComplete instead, there is no lag at all, but the two text components will not have their values updated until the sliding stops, which reduces the effect. My suspicion is that the setState calls inside onValueChange are piling up at a faster rate than than at which they are being processed/completed and it has something to do with other parts of my app. To confirm this, I created a new react native app via react-native init, added that same _renderNameYourPriceModal() to the code, included a button on the screen to open it, and discovered there is no lag at all: http://imgur.com/iZnvDML
How can I determine what is slowing down the setState calls for my existing app? I discovered the React Perf tool and am using it like this to print in the Chrome dev console a summary table.
import Perf from 'react-native/Libraries/Renderer/shims/ReactPerf'
...
componentDidMount() {
setTimeout(() => {
Perf.start()
setTimeout(() => {
Perf.stop()
const measurements = Perf.getLastMeasurements()
Perf.printWasted(measurements)
}, 7000)
}, 1000)
}
According to the Perf docs for printWasted:
printWasted()
Perf.printWasted(measurements)
The most useful part of the profiler.
"Wasted" time is spent on components that didn't actually render
anything, e.g. the render stayed the same, so the DOM wasn't touched.
But I'm not sure how to interpret the results to make the necessary changes. For example, the first four rows of that table when running my app (which has 24 rows in total) looks like this:
I don't know which View the first line, "ItemDetailsScreen > View" inside the Owner > Component column, is referring to because there are 20+ Views on that screen alone. For further context, I'm using React-Navigation and this is a nested screen inside a StackNavigator, although I don't see how updates to this screen's state could cause re-renders in screens further up the hierarchy. Is it necessary to break this screen down further into more custom sub-components so that I override shouldComponentUpdate, or so that the printWasted results tell exactly which areas are at fault?
Here is the function I have for returning the Modal with the Slider inside:
_renderNameYourPriceModal() {
var likelihood = 'Possible'
var lowestVal = 5
var highestVal = 15
if (this.state.nypValue < 6) {
likelihood = 'Nearly Impossible'
} else if (this.state.nypValue < 8) {
likelihood = 'Highly Unlikely'
} else if (this.state.nypValue < 10) {
likelihood = 'Unlikely'
}
return (
<Modal
onRequestClose={() => { this.setState({nypModalVisible: false})}}
animationType={"fade"}
transparent={true}
visible={this.state.nypModalVisible}>
<View style={{paddingTop: 22, height: Dimensions.get('window').height, backgroundColor: 'rgba(252,84,102,0.9)', alignItems: 'center', justifyContent: 'center'}}>
<View
style={{
height: Dimensions.get('window').height * 0.5,
width: Dimensions.get('window').width * 0.9,
backgroundColor: 'white',
borderRadius: 10,
alignItems: 'center'
}}>
<View
style={{flex: 0.8, alignItems: 'center', justifyContent: 'center'}}>
<View style={{flex: 0.25, flexDirection: 'row', width: Dimensions.get('window').width * 0.97, top: -10, alignItems: 'flex-start', justifyContent: 'center'}}>
<View style={{flex: 0.1}}></View>
<View style={{flex: 0.8, alignSelf: 'center', alignItems: 'center', justifyContent: 'center'}}>
<Text style={{fontSize: 23}}>Name Your Price</Text>
</View>
<View style={{flex: 0.1, top: -5, height: 40, alignItems: 'flex-end', justifyContent: 'flex-end'}}>
<TouchableHighlight
underlayColor={'gray'}
style={{height: 40, width: 40, backgroundColor: 'gray', borderRadius: 20, alignItems: 'center', justifyContent: 'center'}}
onPress={() => {
// close
this.setState({nypModalVisible: false})
}}>
<Text style={{fontSize: 25, color: 'white'}}>X</Text>
</TouchableHighlight>
</View>
</View>
<View style={{flex: 0.25, width: Dimensions.get('window').width * 0.8, alignItems: 'center', justifyContent: 'flex-start'}}>
<View style={{flex: 0.5, flexDirection: 'row', alignItems: 'center', justifyContent: 'center'}}>
<View style={{flex: 0.2, alignItems: 'center', justifyContent: 'center'}}>
<Text style={{fontSize: 19}}>${lowestVal.toFixed(2)}</Text>
</View>
<View style={{flex: 0.6, alignItems: 'center', justifyContent: 'center'}}>
<Slider
style={{width: Dimensions.get('window').width * 0.5}}
maximumValue={15}
minimumValue={5}
step={0.5}
value={this.state.nypValue}
// onSlidingComplete={(val) => {
// this.setState({nypValue: val})
// }}
onValueChange={(val) => {
// change value here
this.setState({nypValue: val})
}}
/>
</View>
<View style={{flex: 0.2, alignItems: 'center', justifyContent: 'center'}}>
<Text style={{fontSize: 19}}>${highestVal.toFixed(2)}</Text>
</View>
</View>
<Text>${this.state.nypValue.toFixed(2)}</Text>
<Text>Likelihood: {likelihood}</Text>
</View>
<View style={{flex: 0.5, paddingTop: 20, alignItems: 'center', justifyContent: 'flex-start', paddingHorizontal: 10}}>
<Text style={{textAlign: 'center', top: 25, fontSize: 18}}>Let us know the price you'd like to see this item drop to, and we'll let YOU know when it does!</Text>
</View>
</View>
<View style={{flex: 0.2, alignItems: 'center', justifyContent: 'center'}}>
<TouchableHighlight
style={{height: 50, width: Dimensions.get('window').width * 0.8, alignItems: 'center', justifyContent: 'center', backgroundColor: '#70a8ff', borderRadius: 5}}
underlayColor={'#70a8ff'}
onPress={() => { }}>
<Text style={{fontSize: 20, color: 'white'}}>Set Price Alert</Text>
</TouchableHighlight>
</View>
</View>
</View>
</Modal>
)
}

Resources