I have a simple ListView which seems to take a long time to load its items. I've tested in Release mode, and its taking about 3 seconds to load the whole page. If I set initialListSize={1} I can see it building the list item by item.
The ListView JSX code:
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
renderSeparator={(sectionID, rowID) => <View key={`${sectionID}-${rowID}`} style={styles.separator} />}
style={styles.listView}
initialListSize={1}
/>
And the renderRow method:
renderRow(row) {
// console.log ('rendering scale row: ' + row.numerator + ':' + row.denominator );
return (
<TouchableHighlight onPress={() => this.pressRow(row)} underlayColor="grey">
<View style={styles.rowContainer}>
<Text style={styles.rowText}>{row.hasOwnProperty('label') ? row.label : row.numerator + ':' + row.denominator}</Text>
<Text style={styles.rowText}>{row.hasOwnProperty('label') ? row.numerator + ':' + row.denominator : ''}</Text>
</View>
</TouchableHighlight>
);
}
I'm not doing anything very complicated in renderRow... and the data had already been fetched in a previous view and passed in via props.
Is there something I don't know about that could be affecting load/render time?
This is iOS only and on an iPhone 4S. Only 12-21 rows in my tests.
I should also add that the core of the app is using the JUCE C++ framework and running some audio processing in one of the views. I have an audio processing thread that is only run when that view is visible - all other views (including the one with this ListView) will stop the audio processing thread. I've tried also stopping the audio thread in a similar manner but it did not make any difference.
Not sure if this is going to help you, but I can think of three things you can try...
cmd+T will toggle "slow animations" on/off. This is a long shot
If you are writing to the console.log, comment out those lines. They can surprisingly bog things down considerably sometimes.
Turn off dev mode. You shouldn't need to, but worth a shot
Better start using FlatList or SectionList since ListView is now Deprecated.
https://facebook.github.io/react-native/docs/listview.html
There are few Caveats like you must use a FLUX/ REDUX or RELAY. Please Checkout the details here (Features/Caveats)
https://facebook.github.io/react-native/blog/2017/03/13/better-list-views.html
Related
I'm working on an Expo React Native project that is using react-native-maps to render a MapView component with a list of Markers. The Markers are custom components that render an Image. When testing using Android and Google Maps everything works perfectly. When testing using an iOS emulator the markers appear but the map runs slowly. When testing using a physical iPhone 7 (and others) the app crashes with no error message. The app always loads correctly until rendering the map, which appears for a second or two before the app crashes. Sometimes the markers will also appear for a split second before the app crashes.
If I set limits on how many items to render the markers will appear as long as the limit is less than five. Similarly I can render each marker if I specify which one to load by id, so I don't think the data is wrong or causing unhandled exceptions. I need all the items in the list to render dynamically, without a limit on how many can be rendered. If I comment out the Image component and the default red pin markers appear on the map without any problems. It seems like the issue has to do with how the markers' Images are rendered dynamically on the Apple map.
I've tried importing the image source, preloading it, requiring it, and using {{uri:url}} format for the Image source parameter. Everything results in the app crashing without an error message. Am I missing something? Is there some way for me to get any kind of error message that can help debug this? Is there a workaround if this is a known issue?
MapView:
<MapView
style={styles.map}
ref={(map) => { currentMap = map; }}
region={region}
onRegionChangeComplete={onRegionChange}
rotateEnabled={false}
loadingEnabled
>
{
eventList.map((marker, index) => {
const { location } = marker.location.geometry;
if (
location.lat <= (region.latitude + region.latitudeDelta / 2)
&& location.lat >= (region.latitude - region.latitudeDelta / 2)
&& location.lng <= (region.longitude + region.longitudeDelta / 2)
&& location.lng >= (region.longitude - region.longitudeDelta / 2)
) {
return (
<MapMarker
key={index}
mapMarker={marker}
handlePress={() => moveMapToCoordinate(marker.location)}
onSelectEvent={onSelectEvent}
/>
);
}
return null;
})
}
</MapView>
MapMarker:
<Marker
coordinate={latLng}
title={title}
onPress={() => handlePress()}
>
<CustomMapMarker
eventType={eventType}
isSanctioned={isSanctioned}
startDate={startAt}
/>
<Callout
style={styles.customCallout}
onPress={() => onSelectEvent(_id)}
>
<ViewEventScreenDetailsHeader
fullEvent={mapMarker}
containerStyle={styles.calloutDetails} />
</Callout>
</Marker>
CustomMapMarker:
const img = require('../../assets/icons/SpikeScreen/map-marker-pickup.png');
return (
<View style={[styles.pickupMarkerContainer, markerContainerStyle]}>
<Image
style={[styles.pickupMarker, markerStyle]}
source={img}
/>
<Text style={styles.dayMonthMarkerText}>{formattedStartDate}</Text>
</View>
)
Got em! Make sure your marker icon image isn't too large, Apple maps renders them differently than google maps.
I'm using PureComponent to render items of my FlatList and when I use FlatList and pass a local state to it in data, the rendering works very well, I don't have wasteful re-rendering.
However, when I use FlatList with an array from my redux store in data, if I scroll down, each time that onReachEnd is called, re-render work well. But when I don't have anymore data to load and I scroll up, all my items re-render one per one.
Like my whole list is lost.
I'm using exactly the same list with local state in data, and it works perfectly!
The issue only appear when I try to make FlatList and Redux work together
<FlatList
ref={(view) => this.list = view}
data={this.props.requestsList}
style={{flex: 1}}
keyExtractor={(item) => String(item.emitter.id)}
renderItem={this._renderRequestsItems}
onEndReachedThreshold={0.5}
onEndReached={!this.props.lastPage ? this._endReached : null}
ListFooterComponent={reloadIndicator}
ListHeaderComponent={this._getHeaderComponent}
ListEmptyComponent={this._getEmptyComponent}
/>
Use extraData property on your FlatList component, in your case, extra data can come from props so it will look like
extraData={this.prop}
Can you try to add a new key to flat list?
<FlatList
key={Math.floor(Math.random())}
ref={(view) => this.list = view}
data={this.props.requestsList}
style={{flex: 1}}
keyExtractor={(item) => String(item.emitter.id)}
renderItem={this._renderRequestsItems}
onEndReachedThreshold={0.5}
onEndReached={!this.props.lastPage ? this._endReached : null}
ListFooterComponent={reloadIndicator}
ListHeaderComponent={this._getHeaderComponent}
ListEmptyComponent={this._getEmptyComponent}
/>
It is work for me.
How do I know what native props are available for a component to use setNativeProps. In this example, the <TextInput> component doesn't have text as a prop but apparently setNativeProps use text instead of value as a prop. Thank you!
clearText = () => {
this._textInput.setNativeProps({text: ''});
}
render() {
return (
<View style={{flex: 1}}>
<TextInput
ref={component => this._textInput = component}
/>
<TouchableOpacity onPress={this.clearText}>
<Text>Clear text</Text>
</TouchableOpacity>
</View>
);
}
}
This is pretty common in react-native, due to limited documentation. Whenever looking for any information regarding react-native components, it is a good idea to simply look at the .js file you are using. In this case, TextInput, can be found...
Project/node_modules/react-native/Libraries/Components/TextInput/TextInput.js
Hope you can find what you're looking for - with a bit of digging. If you want to look further, looking into the RCT files is a good idea also.
Project/node_modules/react-native/Libraries/Text/RCTTextField.h
Project/node_modules/react-native/Libraries/Text/RCTTextView.h
I am a newbie developer. I'm currently developing apps using React-Native on two platforms, Android and iOS.
I have several constraints when designing this app on the two platforms I use. This app is similar to chat. For the wrapping compiler I use Listview. But there are constraints when running on the iOS platform.
My code is as follows:
<View style={Styles.container}>
<View style={Styles.conversation}>
{this.messages.length > 0
? <ListView
enableEmptySections
style={Styles.messageList}
ref={ref => (this.listView = ref)}
onContentSizeChange={(contentWidth, contentHeight) => {
this.listView.scrollTo({
y: contentHeight,
});
}
}}
dataSource={ds.cloneWithRows(this.messages)}
renderRow={item => <Message data={item} key={item.key} />}
/>
: <Text style={Styles.welcome_message}>Welcome to Kelle</Text>}
</View>
The code above on Android goes well. But when it runs on iOS, the chat text position in the Listview becomes random. Like the picture below:
Has anyone ever experienced anything like this? How should I solve this problem?
I'm basically asking the same question as this one, but for RN 0.28+. The solutions presented in the various answers do not seem to work in RN 0.28, so I'm hoping there are other configurations or hacks...
Is there any way to resize a WebView based on the height of its content? I've tried injecting the document height into the title and reading that back with onNavigationStateChange, but it always returns 568 (similar to the comments to this gist).
return <TouchableHighlight onPress={() => console.log('touched ' + this.props.choice.id)}
style={styles.choiceRowWrapper} >
<View style={styles.choiceWebViewWrapper}>
<WebView automaticallyAdjustContentInsets={false}
javascriptEnabled={true}
onNavigationStateChange={(navState) => this._updateWebViewNavState(navState)}
scrollEnabled={false}
source={{html: WrapHTML(this.props.choice.text)}}
style={[styles.choiceWebView, {height: this.state.height}]} />
</View>
</TouchableHighlight>
}
_updateWebViewNavState = (navState) => {
console.log(navState);
if (navState.title) {
this.setState({ height: parseInt(navState.title) });
}
}
function WrapHTML (markup) {
return `<!DOCTYPE html>
<html>
<head>
</head>
<body class="content">
${markup}
</body>
<script>window.location.hash = 1;document.title = document.height;</script>
</html>`;
};
I have also tried various things inside of the WebView document, like:
document.scrollHeight.contentSize.height
document.body.height
But all of them are undefined. The closest I got was something like this (from this iOS SO question):
document.getElementById("content").offsetHeight;
But for short text content that returns 20, and for a longer text content (one full sentence) it returns 40...neither of which seems accurate.
I also started trying this RN component, but the repo indicates that it is not being actively maintained -- the latest version on npm doesn't support RN 0.28 because of the change they made for importing React by itself (instead of from ReactNative).
Has anyone gotten WebViews to resize properly with RN 0.28?
After a lot of research and tinkering, I found this approach which is a slightly more involved version of setting the document title to the screen height value. In my tests, this has worked on both Android and iOS with react native 0.47.
https://gist.github.com/xyos/dcaa43fa561760b9d6194d78e5fb7721